题目
分析
依题意,对于一个连通图任意相邻两点不能有两只螃蟹,那么我们很容易想到用染色法来做这道题。一个点要么有螃蟹,要么没有螃蟹,即可用黑白代替,题目就转化为任意一个连通图两点都不能有相同的颜色。
① 对于颜色标记,我们可以用一个变量 t,初始为 0,下次一次标记颜色为 t = t ^ 1 。
② 那么递归结束条件是什么呢 ?第一、如果当前节点已染颜色与当前想要染的颜色 t 不相等,那么就矛盾了,就说明与之前染的颜色不同,那么这个时候就不可能,输出 Impossible,return 0 退出程序。第二、如果当前节点已染颜色与当前想要染的颜色 t 相等,那么说明我们已经染色完了所有点,这个时候就是递归的出口了。
AC代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
int vis[10005], color[10005];
int n, m, nodeNum;
vector<int> edge[10005];
void dfs(int i, int t)
{
if (color[i] != -1 && color[i] != t)// 当前节点有标记但是当前节点与目前该染色矛盾
{
cout << "Impossible" << endl;
exit(0);
}
if (color[i] == t)
{
return;// 标记完了
}
color[i] = t;
vis[i] = 1;
nodeNum++;
for (int j = 0; j < edge[i].size(); j++)
{
dfs(edge[i][j], t ^ 1);// 换一种颜色
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int x, y;
cin >> x >> y;// 存入边
edge[x].push_back(y);
edge[y].push_back(x);
}
int ans = 0;
// memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++)
{
if (vis[i] == 0)
{
nodeNum = 0;
memset(color, -1, sizeof(color));
dfs(i, 0);
int cnt = 0;
for (int i = 1; i <= n; i++)
{
if (color[i] == 1)
{
cnt++;
}
}
ans += min(cnt, nodeNum - cnt);
}
}
cout << ans << endl;
return 0;
}