Description(粗略版)
一些城市,之间有道路相连,现在要安放警卫,警卫能看守到当前点周围的边,一条边只能有一个警卫看守,问是否有方案,如果有最少放几个警卫
Input Sample
2
4 2
0 1
2 3
5 5
0 1
1 2
2 3
0 4
3 4
Output Sample
2
-1
————————————————分割の线————————————————————
其实可以看做是一道二分图的入门题,这里一个连通块中的既可以看成是所有黑点放置守卫,也可以看成是所有白点放置守卫,如果相邻两点的颜色相同则不存在正确放法。值得注意的是如果连通块中只有一个点,则也需要放置警卫,但这时不能比较黑白的个数在放入(思考一下)
详见代码注释:
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
int t,n,m,cnt,cnt1,cnt2,mark,ans;
int b[201],clr[201];
vector<int>g[200],tmp;
void findd(int u,int r)//二分图染色
{
b[u]=1;//记录是否被染过色
clr[u]=r^1;//染色
if(!r) cnt1++;//白色个数++
else cnt2++;//黑色个数++
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!b[v]) findd(v,r^1);//只要不被染色
else if(clr[v]==r^1)//有区域无法被染色(即无法放置守卫)
{
mark=1;//进行标记
return;
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
cnt=mark=ans=0;
memset(b,0,sizeof(b));
memset(clr,0,sizeof(clr));
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
g[i]=tmp;
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);//存图用vector,我自豪
g[x].push_back(y);
g[y].push_back(x);
}//初始化
for(int i=0;i<n;i++)
if(!b[i])//如果未被染色过
{
cnt1=cnt2=0;//染黑和染白的个数均为1
findd(i,0);//二分染色
if(!mark)
{
if(!cnt1||!cnt2) ans++;//如果只被染了一种颜色,则只有一个点且一定要被染色(安放守卫)
else ans+=min(cnt1,cnt2);//取染色后(黑或白)小的部分
}
else break;//如果矛盾,就不需要再做
}
if(mark)//如果无法放置则输出-1
{
printf("-1\n");
continue;
}
printf("%d\n",ans);//输出最少的放置个数
}
return 0;
}