P1330 封锁阳光大学

传送门

思路:

  依题意可知,在图中的每一条边有且只有一个点被选中(阻止老曹刷街),那么就可以对其采取二分图染色,一条边中:一个点为黑色,另一个点为白色;如果一条边中的两个端点的颜色相同,则说明无解,输出:“ Ipossible ";如果有解,就把白点的数目和黑点的数目取 min ,即为答案。

标程:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<queue>
#include<deque>
using namespace std;
#define maxn 100100
int n,m,cnt,ans;
int head[maxn],col[maxn],tot[maxn],vis[maxn];
struct hh
{
    int to,nex;
}t[maxn<<1];
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(!(ls^45))
            kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return xs*kr;
}
inline void add(int nex,int to)
{
    t[++cnt].nex=head[nex];
    t[cnt].to=to;
    head[nex]=cnt;
}
inline bool dfs(int now,int c)//c为1,染上白点;c为0,染上黑点;now要被染色的点 
{
    vis[now]=true;col[now]=c;tot[c]++;//vis记录该点被染色过,col记录这个点染什么颜色
    for(int i=head[now];i;i=t[i].nex)//跑遍这个连通块的所有点 
    {
        int v=t[i].to;
        if(vis[v]&&col[v]==col[now]) return false;
        else if(!vis[v])
        {
            bool sign=dfs(v,(c+1)&1);//另一个端点染的颜色相反(黑→白,白→黑) 
            if(!sign) return false;
        }
    }
    return true;
}
int main()
{
    int x,y;
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        x=read();y=read();
        add(x,y);
        add(y,x);//无向图加边 
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])//该连通块没被染过色 
        {
            tot[0]=tot[1]=0;//tot[0]为黑点,tot[1]为白点 
            bool sign=dfs(i,0);//不仅能够判断有无解,还能染完总这个点起的连通块
            if(!sign)//判断无解 
            {
                printf("Impossible\n");
                exit(0);//直接结束 
            }
            else ans+=min(tot[0],tot[1]);//因为原图不连通,要加上所有连通块的答案。
        }
    }
    printf("%d\n",ans);//输出
return 0;
}

 

posted @ 2018-09-28 21:02  落笔映惆怅丶  阅读(143)  评论(0编辑  收藏  举报