题意:给定n个学生,学生之间可能互相认识。首先需要判断能不能将学生分成两组,使组内学生互相不认识。然后将学生两两分组,保证每一组学生都认识,求最大组数。
思路:交叉染色法判断是不是二分图,然后二分匹配模板。
交叉染色法:首先将一个节点染色,然后将与此相连的节点全部染成另一种颜色,如果有相连节点颜色相同则不是二分图。可以用BFS/DFS写。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
int n,m;
bool path[300][300];
bool used[300];
int match[300];
bool Dfs(int x)
{
used[x] = true;
for (int i = 1; i <= n; i++)
{
if (path[x][i])
{
int w = match[i];
if (w<0 || !used[w]&&Dfs(w))
{
match[x] = i;
match[i] = x;
return true;
}
}
}
return false;
}
int Matching()
{
int ans = 0;
memset(match, -1, sizeof(match));
for (int i = 1; i <= n; i++)
{
if (match[i]<0)
{
memset(used, false, sizeof(used));
if (Dfs(i))
{
ans++;
}
}
}
return ans;
}
bool judge()
{
int col[300];
memset(col, 0, sizeof(col));
col[1] = 1;
queue<int>q;
q.push(1);
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = 1; i <= n; i++)
{
if (path[t][i])
{
if (col[i]==0)
{
col[i] = col[t]==1?2:1;
q.push(i);
}
else if (col[i]==col[t])
{
return false;
}
}
}
}
return true;
}
int main(void)
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while (~scanf("%d %d", &n, &m))
{
memset(path, false, sizeof(path));
while (m--)
{
int x, y;
scanf("%d %d", &x, &y);
path[x][y] = true;
path[y][x] = true;
}
if (!judge())
{
printf("No\n");
continue;
}
int ans = Matching();
printf("%d\n", ans);
}
return 0;
}