HUD2444-二分图

原本是想做POJ2942的,但是不知道二分图染色是怎么回事,就先做了此题

HUD2444--二分图

题目大意:

    求题目中给的图是否为二分图,如果是,求出最大匹配数。

题目解法:

    首先明确几个概念

二分图: 指的是可以用两个不相交的集合表示该图的节点,然后该图的每一条边的端点分别位于这两个集合中。
判断二分图方法:
用染色法,把图中的点染成黑色和白色。
首先取一个点染成白色,然后将其相邻的点染成黑色,如果发现有相邻且同色的点,那么就退出,可知这个图并非二分图。
匈牙利算法
 在介绍匈牙利算法之前还是先提一下几个概念,下面M是G的一个匹配。
   
   
   
   
  M-交错路:p是G的一条通路,如果p中的边为属于M中的边与不属于M但属于G中的边交替出现,则称p是一条M-交错路。如:路径(X3,Y2,X1,Y4),(Y1,X2,Y3)。
  M-饱和点:对于v∈V(G),如果v与M中的某条边关联,则称v是M-饱和点,否则称v是非M-饱和点。如X1,X2,Y1,Y2都属于M-饱和点,而其它点都属于非M-饱和点。
  M-可增广路:p是一条M-交错路,如果p的起点和终点都是非M-饱和点,则称p为M-可增广路。如(X3,Y2,X1,Y4)。(不要和流网络中的增广路径弄混了)
  求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。但是这个算法的时间复杂度为边数的指数级函数。因此,需要寻求一种更加高效的算法。下面介绍用增广路求最大匹配的方法(称作匈牙利算法匈牙利数学家Edmonds于1965年提出)。
  增广路的定义(也称增广轨或交错轨):
  若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
  由增广路的定义可以推出下述三个结论:
  1-P的路径个数必定为奇数,第一条边和最后一条边都不属于M。
  2-将M和P进行取反操作可以得到一个更大的匹配M’。
  3-M为G的最大匹配当且仅当不存在M的增广路径。
  算法轮廓:
  ⑴置M为空
  ⑵找出一条增广路径P,通过异或操作获得更大的匹配M’代替M
  ⑶重复⑵操作直到找不出增广路径为止

时间空间复杂度

  时间复杂度 邻接矩阵:最坏为O(n^3) 邻接表:O(mn)
  空间复杂度 邻接矩阵:O(n^2) 邻接表:O(m+n)

数据分析:

    
    
    
    
4 4 1 2 1 3 1 4 2 3 6 5 1 2 1 3 1 4 2 5 3 6
第一组数据

HUD2444-二分图_第1张图片 

图1  冲突,输出No

第二组数据

HUD2444-二分图_第2张图片不冲突,是二分图

      图2

源码:

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;

#define MAXN 220
#define INF 0x3f3f3f3f

struct Edge
{
	int to;
	int next;
};

int n, m;
int e;
Edge edge[MAXN * MAXN];
int head[MAXN];
int match[MAXN]; 
int col[MAXN]; 
int vis[MAXN];

void addEdge(int u, int v)
{
	edge[e].to = v;
	edge[e].next = head[u];
	head[u] = e;
	e++;
	edge[e].to =u;
	edge[e].next = head[v];
	head[v] = e;
	e++; 
}


void init()
{
	int i, j;
	int u, v;
	e = 0;
	memset(head, -1, sizeof(head));
	memset(match, -1, sizeof(match));
	memset(col, -1, sizeof(col));
	memset(vis, 0, sizeof(vis));
	for(i = 1; i <= m; i++)
	{
		scanf("%d%d", &u, &v);
	 	addEdge(u, v);
	}

}

bool dfs(int u, int fa)
{
	int i;
	int v;
	for(i = head[u]; i != -1; i = edge[i].next)
	{
		v = edge[i].to;
		if(v == fa)
			continue;
		if(col[v] == -1)
		{
			col[v] = col[u] ^ 1;
			dfs(v, u);
		}
			
		else if(col[v] == col[u])
			return false; 
	}
	return true;
}

bool find(int u)
{
	int i;
	int v;
	for(i = head[u]; i != -1; i = edge[i].next)
	{
		v = edge[i].to;
		if(vis[v])
			continue;
		vis[v] = 1;
		if(match[v] == -1 || find(match[v]))
		{
			match[v] = u;
			return true;	
		}
	}	
	return false;
}

void solve()
{
	int i, j;
	int ans;
	while(scanf("%d%d", &n, &m) != EOF)
	{
		ans = 0;
		init();
		col[1] = 1;
		if(!dfs(1, -1))
			printf("No\n");
		else
		{
			for(i = 1; i <= n; i++)
			{
				memset(vis, 0, sizeof(vis));
				if(find(i))
					ans++;
			} 
			printf("%d\n", ans / 2);
		}
	}
}

int main()
{
#ifdef LOCAL
	freopen("hdu2444.txt", "r", stdin);
	// freopen(".txt", "w", stdout);
#endif
	solve();
	return 0;
}

你可能感兴趣的:(数据分析,算法,网络)