题目概述:
有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