题意分析
有一个有向图,要求对点染色为黑或白,满足每一个点的出边连接的与这个点颜色相同的点个数为偶数个。
题解
可行性
本题满足多元关系,即一个点的染色会影响到其他点。
存在环,网络流不好做,所以考虑构造方程组。
条件
一个点已知信息为出边的条数,考虑一组可行解满足的关系。设任意一个点出边
1.当一个点出边条数为奇数时:
1)若该点染色为1:出边到达的点染色为1的为偶数(染色为0的为奇数)。
2)若该点染色为0:出边到达的点染色为0的为偶数(染色为1的为奇数)。
2.当一个点出边条数为偶数时:
1)若该点染色为1:出边到达的点染色为1的为偶数(染色为0的为偶数)。
2)若该点染色为0:出边到达的点染色为0的为偶数(染色为1的为偶数)。
考虑当前方程可行条件:条件是奇偶性,考虑异或方程。发现:
1)出边条数为奇数时,原点和出边到达的点异或和为1。
2)出边条数为奇数时,出边到达的点异或和为0。
建模方法
若存在 i->j 则把矩阵第 i 行第 j 列设为 1。
若 i 出边为奇数,则把矩阵第 i 行第 i 列设为 1。
优化
复杂度
O(n3)
,
109
级别,用bitset优化,常数将为1/32。
bitset
//头文件。
#include<bitset>
//定义。
bitset<2005>a;
bitset<2005>b[2005];
//函数。
b.size()//b中二进制位的个数
b[pos]//访问b中在pos处的二进制位
b.test(pos)//b中在pos处的二进制位是否为1
b.set()//把b中所有二进制位都置为1
b.set(pos)//把b中在pos处的二进制位置为1
b.reset()//把b中所有二进制位都置为0
b.reset(pos)//把b中在pos处的二进制位置为0
b.flip()//把b中所有二进制位逐位取反
b.flip(pos)//把b中在pos处的二进制位取反
b.count()//返回这个bitset中1的个数
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<bitset>
#define R register
using namespace std;
void read(int &aa)
{
R char ch;while(ch=getchar(),ch<'0'||ch>'9');aa=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9')aa=aa*10+ch-'0';
}
int N,b[2010],xx[2010],cnt=0;
bitset<2005>a[2005];
int main()
{
R int i,j,k;
for(i=1,read(N);i<=N;++i)
{
read(j);
if(j&1)a[i].set(i),b[i]=1;
while(j--){read(k);a[i].set(k);}
}
R int col,m,x;
for(i=1,col=1;col<=N;++i)
{
k=i;
for(j=i;j<=N;++j)
if(a[j].test(col))
{k=j;break;}
if(k!=i)
swap(a[i],a[k]),swap(b[i],b[k]);
if(!a[i].test(col))
{++col,--i;continue;}
for(j=i+1;j<=N;++j)
if(a[j].test(col))
a[j]^=a[i],b[j]^=b[i];
++col;
}
for(i=N;i>=1;--i)
{
m=0;
for(j=i+1;j<=N;++j)
m=m^(a[i][j]*xx[j]);
xx[i]=b[i]^m;
if(xx[i]&&!a[i].test(i))
{
printf("Impossible");
return 0;
}
if(xx[i])cnt++;
}
printf("%d\n",cnt);
for(i=1;i<=N;i++)if(xx[i])printf("%d ",i);
return 0;
}