洛谷 P1330 封锁阳光大学
https://www.luogu.org/problemnew/show/P1330
题意:
将一个图染成两种颜色 0 和 1 且由一条边相连接的两个节点不能是相同的颜色。问 能否按照这样的要求实现染色,如果可以的话,最少有多少个节点被染为颜色1。
注意:如果一个节点没有相邻的节点,那么直接把这个节点染成颜色0即可,不可能被染为颜色1。因为题意要求的是颜色1的个数尽可能少。
使用非递归的BFS实现染色,并且在染色过程中记录被染为1号色的点的个数。
考虑到节点交替染成两种颜色,所以在一个联通块中确定一个节点的颜色就可以确定整个联通块的颜色。每个联通块遍历两次,选择1号颜色较少的一种即可。
最后需要判断整个图是否符合要求(染色只负责交替染色,并不能保证图中没有两个颜色相同的点相邻)遍历所有的边即可。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int n,m;
int color1[10004];
int color2[10004];
vector<int> way[10004];
int ans = 0;
int bfs(int p,int c,int* ss)
{
int ret = 0;
queue<int>pp;
pp.push(p);
//int nn = 1;
ss[p] = c;
while(!pp.empty())
{
int from = pp.front();
pp.pop();
int coll = ss[from];
if(coll == 1)
{
ret++;
}
coll ^= 1;
//nn++;
for(int i = 0; i<(int)way[from].size(); i++)
{
if(ss[way[from][i]] != 2)
{
continue;
}
pp.push(way[from][i]);
ss[way[from][i]] = coll;
//nn++;
}
}
//if(nn == 1)
//{
// return 0;
//}
//else
return ret;
}
struct bian
{
int a,b;
} bb[100005];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i<=m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
way[a].push_back(b);
way[b].push_back(a);
bb[i].a = a;
bb[i].b = b;
}
for(int i = 1; i<=n; i++)
{
color1[i] = 2;
color2[i] = 2;
}
for(int i =1; i<=n; i++)
{
if(color1[i]!=2)
{
continue;
}
else
{
ans+=min(bfs(i,1,color1),bfs(i,0,color2));
}
}
int flagok = 1;
for(int i = 1; i<=m; i++)
{
if(color1[bb[i].a] == 1 && color1[bb[i].b] == 1)
{
flagok = 0;
break;
}
if(color1[bb[i].a] == 0 && color1[bb[i].b] == 0)
{
flagok = 0;
break;
}
}
if(flagok == 1)
printf("%d",ans);
else
{
printf("Impossible");
}
}