1. 程式人生 > >【bzoj2466】[中山市選2009]樹 高斯消元

【bzoj2466】[中山市選2009]樹 高斯消元

ai表示每個節點是否按鈕,根據每個點的情況列方程
總共得到n個未知數,n個方程

經過高斯消元后,可能會出現自由元,2^S列舉自由元的選擇,計算答案

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<bitset>
#define maxn 110

using namespace std;

bitset<210> a[maxn];
int c[maxn],b[maxn],ans[maxn];
int n,m,tot;

void gaosixiaoyuan()
{
	memset(b,0,sizeof(b));
	int k=1;
	for (int i=1;i<=n;i++)
	{
		int now=k;
		for (;now<=n;now++) if (a[now][i]==1) break;
		if (now==n+1) {c[++tot]=i;continue;}
		swap(a[now],a[k]);
		for (int j=1;j<=n;j++) if (j!=k && a[j][i]) a[j]^=a[k];
		b[i]=k++;
	}
}

int calc(int x)
{
	int cnt=0;
	for (int i=1;i<=n;i++) ans[i]=a[i][n+1];
	for (int i=1;i<=tot;i++)
	  if (x&(1<<(i-1)))
	  {
	  	cnt++;
	  	for (int j=1;j<=n;j++)
	  	  if (a[j][c[i]]) ans[j]=(!ans[j]);
	  }
	for (int i=1;i<=n;i++) cnt+=ans[i];
	return cnt;
}

int main()
{
	scanf("%d",&n);
	while (n)
	{
		for (int i=1;i<=n;i++) a[i].reset(),a[i][i]=1,a[i][n+1]=1; 
		for (int i=1;i<n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			a[x][y]=1;a[y][x]=1;
		}
		tot=0;
		gaosixiaoyuan();
		int ans=n;
		for (int i=0;i<(1<<tot);i++) ans=min(ans,calc(i));
		printf("%d\n",ans);
		scanf("%d",&n);
	}
	return 0;
}