现在的位置: 首页 > 综合 > 正文

HDUOJ 4751 Divide Groups 2013南京网络赛1004

2014年03月26日 ⁄ 综合 ⁄ 共 1071字 ⁄ 字号 评论关闭

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4751

不得不吐槽一下坑爹的出题人,题目不知道改了多少个。。。不过也就早过一题,晚过一题的问题(因为只A了一题),弱到不能再弱。吃翔去。。。

题目意思就是把一幅有向图的点分成两个集合,使得每个集合内的点构成完全图。

可以转化成二分图,然后染色解决。我们用邻接矩阵保存边,(有正反),然后重新定义连通的关系:如果两个点之间原来有正反两边,那么新的图这两点不相邻,否则相邻,于是得到新图,我们将会得到一些(可能一个)连通片,对于一个连通片相邻的节点必须属于不同集合(原来并不是双向连通),所以可以DFS, 对相邻的点而二染色,当发现将要访问的点已经被染色,则判断他是否是你希望的颜色,不是就矛盾了,否则对于这个连通片,可以二分,而对于不同连通片,完全是独立的,因为没边,说明原来有双向边,可以在同一个集合里。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cstring>
#include<cmath>
using namespace std;
#define N 105
#define sl(s) strlen(s)
#define mem(a) memset(a, 0, sizeof(a))
#define dou double

int s[105][105], vis[105], x[105][105], fl, c[105];

void dfs(int x, int d){
	int i, j, k;
	vis[x] = 1;
	c[x] = d & 1;
	if (!fl) return ;
	for (i = 1; i <= n; ++i){
		if (x[x][i]){
			if (vis[i]){
				if (c[i] + c[x] != 1) fl = 0; 
			}
			else{
				dfs(i, d + 1);
			}
		}
	}
}


int main(){
	int n, i, j, k;
	while (cin >> n){
		mem(s), mem(vis), mem(c), mem(x)
		for (i = 1; i <= n; ++i)
			while (cin >> tem, tem) s[i][tem] = 1;
		for (i = 1; i <= n; ++i)
			for (j = i + 1; j <= n; ++j)
				if (s[i][j] + s[j][i] == 1){
					x[i][j] = x[j][i] = 1;
				}
		fl = 1;
		for (i = 1; i < n; ++i){
			if (vis[i]) dfs(i, 0);
		}
		if (fl) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

抱歉!评论已关闭.