图的二色染色

洛谷 P1330 封锁阳光大学
https://www.luogu.org/problemnew/show/P1330

题意:
将一个图染成两种颜色 01 且由一条边相连接的两个节点不能是相同的颜色。问 能否按照这样的要求实现染色,如果可以的话,最少有多少个节点被染为颜色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");
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值