2466: [中山市选2009]树
Submit: 1416 Solved: 614
[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。
高斯消元,dfs求自由元
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 const int MAXN=105; 7 const int INF=0x7f7f7f7f; 8 int n,ans; 9 bool a[MAXN][MAXN],A[MAXN]; 10 11 void gauss() 12 { 13 for(int i=1;i<=n;i++) 14 { 15 int r=i; 16 while(r<=n&&!a[r][i]) r++; 17 if(!a[r][i]) continue; 18 if(i!=r) 19 for(int j=i;j<=n+1;j++) 20 swap(a[i][j],a[r][j]); 21 for(int j=i+1;j<=n;j++) 22 if(a[j][i]) 23 for(int k=n+1;k>=i;k--) 24 a[j][k]^=a[i][k]; 25 } 26 } 27 28 void dfs(int x,int now) 29 { 30 if(now>=ans) return; 31 if(!x){ans=now;return;} 32 if(a[x][x]) 33 { 34 A[x]=a[x][n+1]; 35 for(int i=x+1;i<=n;i++) 36 A[x]^=a[x][i]*A[i]; 37 dfs(x-1,now+A[x]); 38 } 39 else 40 { 41 A[x]=0;dfs(x-1,now); 42 A[x]=1;dfs(x-1,now+1); 43 } 44 } 45 46 int main() 47 { 48 while(scanf("%d",&n)) 49 { 50 if(n==0) break; 51 memset(a,0,sizeof(a)); 52 for(int i=1;i<n;i++) 53 { 54 int x,y; 55 scanf("%d%d",&x,&y); 56 a[x][y]=a[y][x]=1; 57 } 58 for(int i=1;i<=n;i++) a[i][i]=a[i][n+1]=1; 59 gauss(); 60 ans=INF; 61 dfs(n,0); 62 printf("%d\n",ans); 63 } 64 return 0; 65 }