Even separation jzoj 4551 高斯消元法解异或方程组

来源:互联网 发布:知る是几段动词 编辑:程序博客网 时间:2024/06/05 02:11

题目大意

这里写图片描述

分析

将点 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);}
原创粉丝点击