HDU 5971 [二分图染色]

题目链接

//二分图染色法(依次染色)
//首先要确定所有人都被限定过,否则直接输出no,
//再将已经确定好good和bad的人进行染色,判断有没有发生冲突,冲突输出no,
//最后将剩下还没染色的人依次染色(由于再前一次染色并未被染色,说明对剩下的染色不会和已染的人发生冲突,只要判断对剩下的人染色时是否冲突即可),冲突输出no,到最后还未输出no则输出yes
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10, M = 1e4 + 10; 
int e[M], ne[M], h[N], vis[N] ,idx;
int cl[N];

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;//链式前向星加边
}

void reset(int m,int n){
    for(int i=1;i<=m;i++){
        e[i]=0;
        ne[i]=0;
    }
    for(int i=1;i<=n;i++){
        cl[i]=0;
        vis[i]=0;
        h[i]=0;
    }
    idx=1;//从1开始,防止dfs时循环判断条件i是否未零出错(de了半小时这个)
}//初始化数据

bool dfs(int n,int clo){
    cl[n]=clo;
    for(int i=h[n];i;i=ne[i]){
        int to=e[i];
        if(cl[n] == cl[to]) return 0;//染色冲突
        if(!cl[to]){
            if(!dfs(to,3-clo)) return 0;//未染色则dfs继续染色,直到相关点全部被染色
        }
    }
    return 1;
}

void solve(int n){
    for(int i=1;i<=n;i++){//如果有点没有限制条件,则无法确定直接输出no
        if(vis[i]==0){
            printf("NO\n");
            return;
        }
    }
    for(int i=1;i<=n;i++){//对颜色确定的点染色
        if(cl[i]){
            if(!dfs(i,cl[i])){//冲突输出no
                printf("NO\n");
                return;
            }
        }
    }
    for(int i=1;i<=n;i++){//对第一轮染色未被染色的点染色
        if(!cl[i]){
            if(!dfs(i,1)){//冲突输出no(此处染1,2均可,因为此时尚未染色的点和前面的点相互独立,只要判断剩下的点是否构成二分图即可)
                printf("NO\n");
                return;
            }
        }
    }
    printf("YES\n");
    return;
}
int main(){
    int m,n,x,y;
    while(~scanf("%d%d%d%d",&n,&m,&x,&y)){
        reset(m,n);
        for(int i=1;i<=m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
            vis[a]=1;
            vis[b]=1;
        }
        for(int i=1;i<=x;i++){
            int xn;
            scanf("%d",&xn);
            vis[xn]=1;
            cl[xn]=1;
        }
        for(int i=1;i<=y;i++){
            int yn;
            scanf("%d",&yn);
            vis[yn]=1;
            cl[yn]=2;
        }//输入
        solve(n);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值