洛谷 P1330 封锁阳光大学 二分图染色

题目描述

曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

阳光大学的校园是一张由N个点构成的无向图,N个点之间由M条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在与这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

输入输出格式

输入格式:

第一行:两个整数N,M

接下来M行:每行两个整数A,B,表示点A到点B之间有道路相连。

 

输出格式:

仅一行:如果河蟹无法封锁所有道路,则输出“Impossible”,否则输出一个整数,表示最少需要多少只河蟹。

 

输入输出样例

输入样例#1: 复制
3 3
1 2
1 3
2 3
输出样例#1: 复制
Impossible
输入样例#2: 复制
3 2
1 2
2 3
输出样例#2: 复制
1

说明

【数据规模】

1<=N<=10000,1<=M<=100000,任意两点之间最多有一条道路。

 

这个题目思路是染黑白色,但真的好难想(看了大佬题解后才恍然大悟),我们画图来理解下

样例1的图

选择封锁任意一个点都是可以的,这里我们选择1

可以看到,1-2和1-3的道路走不了了。但是由于选择了1,那么2,3都不能选了(河蟹会起冲突),因此2-3无法封锁

我们用染色的角度来看,1染成白色(用0表示),那么它连到的所有点都要染成黑色(用1表示),可以发现只有一条边两边的点颜色不同才能保证完成封锁

通过上面的分析可以得出完成封锁的条件

1.任意一条边所连得两个点至少有一个被选择

2.任意一条边两边点的颜色不能相同

染黑白色即可

但是这里还有很重要的一点,这个图,不一定是联通的!!!不一定是联通的!!!不一定是联通的!!!(一开始挂掉的原因)所以我们要开个数组记录一下到过哪些点,确保每一个子图都走到;对于每一个子图,如果能封锁,要取黑色和白色中花费最小的(河蟹放黑色点或者放白色点都是可行的)最后汇总一下所有子图的结果就是答案了;如果不能封锁(发现有相邻两个点的颜色相同),直接输出Impossible,结束程序即可

完整代码

#include<bits/stdc++.h>
using namespace std;
vector <int>  edge[1000010];
queue <int> que;
int vis[1000010],ans[2],col[1000010];
int n,m,ansn,aa,bb,flag;
void bfs(int x)
{
    while(!que.empty())
    {
        int tmp=que.front();
        que.pop();
        vis[tmp]=1;
        for(int i=0;i<edge[tmp].size();i++)
        {
            int nowp=edge[tmp][i];
            if(col[nowp]==col[tmp])//如果相邻两个点的颜色一致
            {
                cout<<"Impossible";//输出
                exit(0);//走人
            } 
            if(!vis[nowp])//不一致
            {
                que.push(nowp);
                col[nowp]=(col[tmp]+1)%2;//染反色
                ans[col[nowp]]++;//对应颜色的花费+1
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>aa>>bb;
        edge[aa].push_back(bb);//无向图正反都要连
        edge[bb].push_back(aa);
    }
    memset(col,-1,sizeof(col));//初始化颜色数组
    for(int i=1;i<=n;i++)
    {
        if(vis[i]!=1)  //如果不在之前的子图中
        {
            ans[0]=1; //染白色的花费初始化1
            ans[1]=0;//染黑色的为0
            col[i]=0;//默认白色开始染
            que.push(i);
            bfs(i);//开始染色
            ansn+=min(ans[0],ans[1]);//总花费加上黑白色中花费少的
        }
    }
      cout<<ansn;//快乐的输出
      return 0;
}

参考大佬@KesdiaelKen@hxn2228的题解

posted @ 2018-08-21 20:49  pcpcppc  阅读(133)  评论(0编辑  收藏  举报