题目大意
分析
将点 i 看为变量 xi,取值 0, 1,表示点在A、B部分。
设 di 为点 i 在原图中的点度
如果 di 为偶数,那么只需要让与它相邻的点异或起来为 0 即可。
∑ (i,j)∈E xj ≡ 0 (mod 2)
如果 di 为奇数,那么要让它与它相邻的点异或起来为 1。
xi + ∑ (i,j)∈E xj ≡ 1 (mod 2)
用高斯消元解异或方程即可。
异或方程组就是形如这个样子的方程组:
M[0][0]x[0]^M[0][1]x[1]^…^M[0][N-1]x[N-1]=B[0]
M[1][0]x[0]^M[1][1]x[1]^…^M[1][N-1]x[N-1]=B[1]
…
M[N-1][0]x[0]^M[N-1][1]x[1]^…^M[N-1][N-1]x[N-1]=B[N-1]
其中“^”表示异或(XOR, exclusive or),M[i][j]表示第i个式子中x[j]的系数,是1或者0。B[i]是第i个方程右端的常数,是1或者0。
解这种方程可以套用高斯消元法,只须将原来的加减操作替换成异或操作就可以了,两个方程的左边异或之后,它们的公共项就没有了。
分析
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int x[1000];
struct arr{
int x,y;
int next;
}edge[1000000];
int edge_m;
int ls[1000];
int du[1000];
int n,m;
void add(int x,int y)
{
edge_m++;
du[x]++;
edge[edge_m]=(arr){x,y,ls[x]};ls[x]=edge_m;
edge_m++;
du[y]++;
edge[edge_m]=(arr){y,x,ls[y]};ls[y]=edge_m;
}
int b[1000];
int a[1000][1000];
int main()
{
//freopen("even.in", "r", stdin);
//freopen("even.out", "w", stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
a[x][y]=1;
a[y][x]=1;
}
for (int i=1;i<=n;i++)
{
if (du[i]%2==0)
b[i]=0;
else
{
b[i]=1;
a[i][i]=1;
}
}
for (int i=1;i<=n;i++)
{
int k=i;
int c=0;
for (int j=i+1;j<=n;j++)
if (a[j][i])
{
k=j;
continue;
}
for (int j=1;j<=n;j++)
{
c=a[i][j];
a[i][j]=a[k][j];
a[k][j]=c;
}
c=b[i]; b[i]=b[k]; b[k]=c;
for (int j=1;j<=n;j++)
{
if ((j==i)||(!a[j][i])) continue;
b[j]^=b[i];
for (int l=1;l<=n;l++)
a[j][l]^=a[i][l];
}
}
for (int i=1;i<=n;i++)
x[i]=b[i];
int flag=0;
for (int i=1;i<=n;i++)
if (x[i])
flag++;
if ((flag==n)||(flag==0))
{
printf("NO");
fclose(stdin);
fclose(stdout);
return 0;
}
printf("YES\n");
for (int i=1;i<=n;i++)
{
if (x[i])
printf("A");
else
printf("B");
}
fclose(stdin);
fclose(stdout);
}