2466: [中山市选2009]树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 854 Solved: 361
[ Submit][ Status][ Discuss]
Description
图论中的树为一个无环的无向图。给定一棵树,每个节点有一盏指示灯和一个按钮。如果节点的按扭被按了,那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭(当按之前是点亮的)。并且该节点的直接邻居也发生同样的变化。
开始的时候,所有的指示灯都是熄灭的。请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。
Input
输入文件有多组数据。
输入第一行包含一个整数n,表示树的节点数目。每个节点的编号从1到n。
输入接下来的n – 1行,每一行包含两个整数x,y,表示节点x和y之间有一条无向边。
当输入n为0时,表示输入结束。
Output
对于每组数据,输出最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。每一组数据独占一行。
Sample Input
3
1 2
1 3
0
1 2
1 3
0
Sample Output
1
HINT
对于100%的数据,满足1 <= n <=100。
Source
题解:高斯消元
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 103
using namespace std;
int mn,now,b[N],a[N][N],n,ans[N];
void dfs(int i)
{
if (!i) {
mn=min(mn,now);
return;
}
if (now>=mn) return;
if (a[i][i]) {
for (int j=i+1;j<=n;j++)
if (a[i][j]) b[i]^=ans[j];
ans[i]=b[i];
if (b[i]) now++; dfs(i-1);
if (b[i]) now--;
for (int j=i+1;j<=n;j++)
if (a[i][j]) b[i]^=ans[j];
}
else {
ans[i]=1; now++; dfs(i-1);
ans[i]=0; now--; dfs(i-1);
}
}
void guass()
{
for (int i=1;i<=n;i++) {
int num=i;
for (int j=i+1;j<=n;j++)
if (a[j][i]) {
num=j;
break;
}
if (num==i) continue;
for (int j=1;j<=n;j++) swap(a[num][j],a[i][j]);
swap(b[i],b[num]);
for (int j=i+1;j<=n;j++)
if (a[j][i]) {
for (int k=1;k<=n;k++) a[j][k]^=a[i][k];
b[j]^=b[i];
}
}
dfs(n);
}
int main()
{
freopen("a.in","r",stdin);
while (true) {
scanf("%d",&n);
if (!n) break;
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
memset(ans,0,sizeof(ans));
for (int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
a[x][y]=a[y][x]=1;
}
for (int i=1;i<=n;i++) a[i][i]=1;
for (int i=1;i<=n;i++) b[i]=1;
mn=100000000; guass();
printf("%d\n",mn);
}
}