HDU 4751 交叉染色判断二分图

37 篇文章 1 订阅
22 篇文章 0 订阅

九野的博客,转载请注明出处:http://blog.csdn.net/acmmmm/article/details/11877509

修改后的题意是:

n个点,下面n行

i行表示与i点相连的单向边,为0表示该行输入结束

问: 把点分到2个图中,每个图都要保证是完全图能否做到

问题等价于 保证不认识的不在同一个图里

 显然这个图的补图就是一个二分图,BFS交叉染色判断图是否为二分图

 

代码1:

 

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <queue>
#include <stdlib.h>
#include <cstdlib>
#include <math.h>
#include <set>
#include <vector>
#define inf 107374182
#define N 200
#define M 20001
#define ll int
using namespace std;
inline ll Max(ll a,ll b){return a>b?a:b;}
inline ll Min(ll a,ll b){return a<b?a:b;}
struct Edge{
	int f,t;
}edge[M];
int edgenum;
void addedge(int u,int v){
	Edge E={u,v,};
	edge[edgenum]=E;
	edgenum++;
}
//不认识的人一定在不同集合
int map[N][N];
int in[N],n;
bool BFS(int x){
	queue<int>q;
	q.push(x);
	in[x]=0;
	while(!q.empty()){
		x=q.front(); q.pop();
		for(int i=1;i<=n;i++)
		{
			if(i==x || map[i][x]==1)continue;//x和i认识就不用考虑
			if(in[i]==-1)
			{
				in[i]=in[x]^1;
				q.push(i);
			}
			else if(in[i]==in[x])return 1;
		}
	}
	return 0;
}
int main()
{
	int i,j,m;
	while(~scanf("%d",&n)){
		edgenum=0;
		memset(map,0,sizeof(map));
		for(i=1;i<=n;i++){
			scanf("%d",&m);
			while(m!=0){
				map[i][m]=true;
				scanf("%d",&m);
			}
		}
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				if(map[i][j]==0)map[j][i]=0;
		memset(in,-1,sizeof(in));
		for(i=1;i<=n;i++)
			if(in[i]==-1)
				if(BFS(i))break;
		
		if(i>n)printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}


 

 

贴个学长的代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//const int inf = 1000000000;
const int N = 500;
const int M = N*N;

struct E{
    int v,next;
}e[M];
int head[N],k;
int belong[N],bcnt,dfn[N],low[N],ind;
int stack[N],top;
bool vis[N];
int n;
void add(int u,int v){
    e[k].v = v;
    e[k].next = head[u];
    head[u] = k++;
}
void tarjan(int u){
    dfn[u] = low[u] = ++ind;
    vis[u] = true;
    stack[top++] = u;
    for(int i=head[u] ; i!=-1 ; i=e[i].next){
        int v = e[i].v;
        if(!dfn[v]){
            tarjan(v);
            if(low[u] > low[v])
                low[u] = low[v];
        }else if(vis[v] && dfn[v] < low[u])
            low[u] = dfn[v];
    }
    if(low[u] == dfn[u]){
        bcnt++;
        int temp;
        do{
            temp = stack[--top];
            vis[temp] = false;
            belong[temp] = bcnt;
        }while(u != temp);
    }
}
void init(){
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    k = top = ind = bcnt = 0;
}
int mp[N][N];
bool ok()
{
    bool flag=1;
    int i;
    init();
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(mp[i][j]==0||mp[j][i]==0)
            {
                add(i,j+n);
                add(j,i+n);
                add(i+n,j);
                add(j+n,i);
            }
    for(i=1 ; i <= 2*n ; ++i)
        if(!dfn[i]) tarjan(i);
    for(i=1 ; i <=n ; ++i)
        if( belong[i] == belong[i+n] )
            flag=0;
    return flag;
}
int main()
{
    int x;
    while(scanf("%d",&n)!=EOF)
    {
        memset(mp,0,sizeof(mp));
        for(int i=1;i<=n;i++)
        {
            while(1){
                scanf("%d",&x);
                if(x==0)
                    break;
                mp[i][x]=1;
            }
        }
        if(ok())
            printf("YES\n");
        else
            printf("NO\n");

    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值