【二分图染色】[UVA11080] Place the Guards 城市警卫

Description(粗略版)

一些城市,之间有道路相连,现在要安放警卫,警卫能看守到当前点周围的边,一条边只能有一个警卫看守,问是否有方案,如果有最少放几个警卫

PDF(English)

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;  
}  

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/80145548
今日推荐