hdu 4751 Divide Groups (2-SAT or 补图+二分图判定)

有一群人,有的人认识某些人(认识的关系是单向的)。

现在需要将这些人分成两个部分,一个部分中所有的人都是两两认识的。

2SAT,每个人要么属于第一个集合,要么属于第二个集合。

补图+二分图判定。

#include<iostream>    
#include <cstdio>    
#include <cstring>    
#include <algorithm>    
using namespace std;    
const int maxn = 102;    
int g[maxn][maxn];    
int col[maxn];    
int n;    
bool is_bi(int u){    
    for (int i=1; i<=n; i++){    
        if (g[u][i] && u!=i){    
            if (col[i] == col[u])    
                return false;    
            if (!col[i]){    
                col[i] = 3 - col[u];    
                if (!is_bi(i))    
                    return false;    
            }    
        }    
    }    
    return true;    
}    
int main(){    
    int p;    
    int i, j, k;    
    while (scanf("%d",&n)!=EOF){    
        memset(g, 0, sizeof(g));    
        memset(col, 0, sizeof(col));    
        for (i=1; i<=n; i++){    
            while (scanf("%d",&p),p){    
                g[i][p] = 1;    
            }    
        }    
        for (i=1; i<=n; i++){    
            for (j=i+1; j<=n; j++){    
                if (g[i][j] && g[j][i]){    
                    g[i][j] = g[j][i] = 0;    
                }    
                else g[i][j] = g[j][i] = 1;    
            }    
        }    
        int flag = 0;    
        for (i=1; i<=n; i++){    
            if (!col[i]){    
                col[i] = 1;    
                if (!is_bi(i)){    
                    flag = 1;    
                    break;    
                }    
            }    
        }    
        if (flag)printf("NO\n");     
              else printf("YES\n");    
    }    
    return 0;    
}    

#include<iostream>  
#include<cstring>  
#include<cstdio>  
using namespace std;  
#define clr(x)memset(x,0,sizeof(x))  
int abs(int x){if(x>0)return x;return -x;}  
const int maxn=10010;  
struct node{  
    int to;  
    int next;  
}q[10010];  
int head[maxn];  
int tot;  
void add(int s,int u){  
    q[tot].to=u;  
    q[tot].next=head[s];  
    head[s]=tot++;  
}  
bool ins[maxn];  
int color[maxn];  
int dfn[maxn],low[maxn],stack[maxn];  
int ti,sn,top;  
void tarjan(int u){  
    dfn[u]=low[u]=++ti;  
    stack[++top]=u;  
    ins[u]=true;  
    int i,k;  
    for(i=head[u];i;i=q[i].next){  
        k=q[i].to;  
        if(dfn[k]==0){  
            tarjan(k);  
            if(low[k]<low[u])low[u]=low[k];  
        }  
        else if(ins[k]&&dfn[k]<low[u])  
            low[u]=dfn[k];  
    }  
    if(dfn[u]==low[u]){  
        sn++;  
        do{  
            k=stack[top--];  
            ins[k]=false;  
            color[k]=sn;  
        }while(k!=u);  
    }  
}  
void init(){  
    clr(low);  
    clr(dfn);  
    clr(ins);  
    clr(head);  
    tot=1;  
    top=-1;  
    sn=ti=0;  
}  
int g[300][300];  
int main(){  
    int i,j,n,p;  
    while(scanf("%d",&n)!=EOF){  
        init();  
        clr(g);  
        for (i=0;i<n;i++){  
            while(scanf("%d",&p),p){  
                p--;  
                g[i][p] = 1;  
            }  
        }  
        for(i=0;i<n;i++){  
            for (j=i+1;j<n;j++){  
                if (g[i][j]&&g[j][i]){  
                   g[i][j]=g[j][i]=0;  
                }  
                else {g[i][j]=g[j][i]=1;add(i,j+n);add(j,i+n);add(i+n,j);add(j+n,i);}  
            }  
        }  
        for(i=0;i<2*n;i++)  
        if(dfn[i]==0)tarjan(i);  
        int flag=0;  
        for(i=0;i<n;i++)  
        if(color[i]==color[i+n])flag=1;  
        if(flag)printf("NO\n");  
        else printf("YES\n");  
    }  
    return 0;  
}  


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值