hdu 2444

题目概述:

有N个人,M组互相认识关系

互相认识的两人分别为a,b,将所有人划分为两组,使同一组内任何两人互不认识,之后将两个组中互相认识的人安排在一个房间,如果出现单人的情况则不安排房间

输入:

第一行N,M,其后M行,每行a,b,输入有多组,到EOF为止

限制:

1<N<=200;

输出:

如果无法划分为如此两组,为一个字符串:

No

否则,为一个整数,需要安排的最大房间数

多组输出之间没有空行

样例输入:

4 4
1 2
1 3
1 4
2 3
6 5
1 2
1 3
1 4
2 5
3 6
1 0

样例输出:

No
3
0

讨论:

这个题本身是有问题的,数据太弱,从讨论版可以看到这一点,这点不仅使得当作有向图考虑可行(按题目要求应为无向图),甚至导致同一组输入可以有多组合法输出,这个题仅适合用于学习二分图判断代码,不宜深究其逻辑

讨论:

题解状态:

46MS,1752K,1441 B,C++

#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f
#define maxx(a,b) ((a)>(b)?(a):(b))
#define minn(a,b) ((a)<(b)?(a):(b))
#define MAXN 205

int N, M;
bool f;//flag,如果是二分图为false,否则为true
bool edges[MAXN][MAXN];
int marked[MAXN];
int edgeto[MAXN];
bool hungary(int a)
{
	for (int p = 1; p <= N; p++) {
		if (edges[a][p] && !marked[p]) {
			marked[p] = true;
			if (!edgeto[p] || hungary(edgeto[p])) {
				edgeto[p] = a;
				return true;
			}
		}
	}
	return false;
}
void dfs(int a, int mk)//深搜节点a,并为其携带一个非零标记
{
	marked[a] = mk;//标记该节点
	for (int p = 1; p <= N; p++) {//遍历所有节点
		if (edges[a][p]) {//如果存在路
			if (a != p&&marked[p] == mk) {//这个节点非其本身但带了和其同样的标记
				f = true;//这不是合法二分图
				return;//返回
			}
			else if (!marked[p])//如果根本没带标记
				dfs(p, -mk);//换成另一个标记继续深搜
		}
		if (f)//某次深搜后已经判定非二分图
			return;//一路返回
	}
}
void fun()
{
	for (int p = 0; p < M; p++) {
		int a, b;
		scanf("%d%d", &a, &b);//input
		edges[a][b] = true;
	}//input ends here
	memset(marked, 0, sizeof(marked));
	for (int p = 1; p <= N; p++) {
		if (!marked[p])
			dfs(p, 1);
	}
	if (f) {
		printf("No\n");//output
		return;
	}
	int cnt = 0;
	for (int p = 1; p <= N; p++) {
		memset(marked, 0, sizeof(marked));
		if (hungary(p))
			cnt++;
	}
	printf("%d\n", cnt);//output
}
int main(void)
{
	//freopen("vs_cin.txt", "r", stdin);
	//freopen("vs_cout.txt", "w", stdout);

	while (~scanf("%d%d", &N, &M)) {//input
		fun();
		memset(edges, 0, sizeof(edges));
		memset(edgeto, false, sizeof(edgeto));
		f = false;
	}
}

EOF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值