把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

点此看题面

  • 给定一张\(n\)个点\(m\)条边的无向图,要求把这张图划分为两个点集(可以有一个为空),删去不同点集间的连边。
  • 要求构造一组方案,最大化度数为偶数的点数。
  • \(n\le200\)

一个奇怪的定理

奇怪的定理又增加了。。。

The Gallai Cycle-Cocycle Partition Theorem(证明请自行查阅原论文)告诉我们,一定存在一种点集划分方案,使得所有点度数都是偶数

所以我们只要考虑怎么构造一组方案就好了。

高斯消元

设一个点集中的所有点\(x_i=0\),另一个点集中\(x_i=1\)

判断\(i,j\)是否在同一点集可以写成\(x_i\oplus x_j\oplus1\)

则对于每个点,可以列出一个方程:

\[\bigoplus_{(i,j)\in E}(x_i\oplus x_j\oplus 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\n",t),i=1;i<=n;++i) v[i]&&printf("%d ",i);return 0;//取出x[i]=1的点集
}
posted @ 2021-05-20 18:06  TheLostWeak  阅读(92)  评论(0)    收藏  举报