【洛谷3429】[POI2005] DWA-Two Parties(高斯消元)

点此看题面

  • 给定一张(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的点集
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3429.html