这道题有两种解法,一种是用并查集,还有一种是DFS
对于第一种解法的思路是:
只要不形成环,就可二着色。
开两个数组,a用来存点,跟之前的并查集一样,每个连通域都用一个代表元素来表示。数组b用来存着色情况。
首先,初始化数组a,a[i]=i。初始化数组b,b[i]=0;
然后每次进来的两个数,若b[x]=b[y]=0,就分别上色1,-1。若一个为0,一个非0,则对0的着上相反的颜色。若二者都着过色,用并查集查找函数,找出其的祖先,看祖先是否相同,若相同,说明形成环了,不可二着色。否则继续。每次循环都将两个点用并查集合并函数进行合并。
代码:
#include <stdio.h>
#define MAX 100001
int a[MAX],b[MAX]={0};
int flag=0;
void init_a(int n)
{
int i;
for(i=1;i<=n;i++)
a[i]=i;
}
int find(int x)
{
int j=x;
while(j!=a[j])
j=a[j];
return j;
}
void Union(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
a[fx]=fy;
}
}
int main()
{
int n,m,i,x,y;
scanf("%d%d",&n,&m);
init_a(n);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(b[x]==0&&b[y]==0)
{
b[x]=1;
b[y]=-1;
}
else if(b[x]!=0&&b[y]!=0)
{
if(b[x]==b[y])
{
if(find(x)==find(y))
flag=1;
}
else if(b[x]!=0&&b[y]==0)
{
b[y]=-b[x];
}
else if(b[x]==0&&b[y]!=0)
{
b[x]=-b[y];
}
}
Union(x,y);
}
if(flag==1)
printf("No\n");
else
printf("Yes\n");
return 0;
}
/*
8 7
1 3
1 6
2 8
3 7
4 5
5 6
5 8
*/
还有一种就是用图遍历的方式。由于这题的数据量比较大,所以不能用邻接矩阵表示,会超内存。所以选用邻接表。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
#define MAX_NUM 100005
struct node
{
int v;
node *next;
node(int _v=0,node *_next=NULL):v(_v),next(_next){}
}*edge[MAX_NUM*2];
void add(int u,int v)
{
edge[u]=new node(v,edge[u]);
edge[v]=new node(u,edge[v]);
}
int flag,vex[MAX_NUM];
void dfs(int u,int c)
{
int v;
vex[u]=c;
for(node *p=edge[u];p;p=p->next)
{
v=p->v;
if(vex[v]==-1)
dfs(v,!vex[u]);
else if(flag==0&&vex[v]==vex[u])
{
flag=1;
printf("No\n");
}
}
}
int main(){
int n,m,x,y,i;
scanf("%d%d",&n,&m);
flag=0;
memset(vex,-1,sizeof(vex));
while(m--)
{
scanf("%d%d",&x,&y);
add(x,y);
}
if(m>=n)
printf("No\n");
else
{
for(i=1;i<=n;i++)
if(flag==0&&vex[i]==-1) dfs(i,0);
if(flag==0)
printf("Yes\n");
}
return 0;
}