- 给定一张(n)个点(m)条边的无向图,要求把这张图划分为两个点集(可以有一个为空),删去不同点集间的连边。
- 要求构造一组方案,最大化度数为偶数的点数。
- (nle200)
一个奇怪的定理
奇怪的定理又增加了。。。
The Gallai Cycle-Cocycle Partition Theorem(证明请自行查阅原论文)告诉我们,一定存在一种点集划分方案,使得所有点度数都是偶数。
所以我们只要考虑怎么构造一组方案就好了。
高斯消元
设一个点集中的所有点(x_i=0),另一个点集中(x_i=1)。
判断(i,j)是否在同一点集可以写成(x_ioplus x_joplus1)。
则对于每个点,可以列出一个方程:
[igoplus_{(i,j)in E}(x_ioplus x_joplus 1)=0
]
高斯消元解一下就好了。
代码:(O(n^3))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
using namespace std;
int n,a[N+5][N+5],v[N+5];I void Gauss()//高斯消元模板
{
RI i,j,k;for(i=1;i<=n;++i)
{
if(!a[i][i]) {for(j=i+1;j<=n&&!a[j][i];++j);for(k=i;k<=n;++k) swap(a[i][k],a[j][k]);swap(v[i],v[j]);}
for(j=i+1;j<=n;++j) if(a[j][i]) for(v[j]^=v[i],k=i;k<=n;++k) a[j][k]^=a[i][k];
}
for(i=n;i;--i) if(v[i]) for(j=i-1;j;--j) a[j][i]&&(v[j]^=1);
}
int main()
{
RI i,x,y;for(scanf("%d",&n),i=1;i<=n;++i) for(scanf("%d",&x);x;--x) scanf("%d",&y),a[i][y]=1,a[i][i]^=1,v[i]^=1;//列方程
RI t=0;for(Gauss(),i=1;i<=n;++i) v[i]&&++t;for(printf("%d
",t),i=1;i<=n;++i) v[i]&&printf("%d ",i);return 0;//取出x[i]=1的点集
}