题意
给定一棵树。每个点被按以后,与它直接相连的点会发生变换(亮变不亮,不亮变亮),每个点最初都是熄灭的,问最少多少次可以使所有点都变暗
题解
显然每个点最多按一次。
我们把相连的两个点连边,解异或方程组
这样所有的主元就是必须要按的
然后取枚举自由元选不选,深搜就可以了
代码
#include <cstdio>
#include <cstring>
#include <bitset>
#include <algorithm>
using namespace std;
#define N 110
int n,tot=0,ans,pivot[N],lib[N],val[N];
bitset<N> a[N];
inline void guass(){
int now=1;
for(int i=1;i<=n;i++){
int r=now;
while(!a[r][i] && r<=n) r++;
if(r>n){lib[++tot]=i;continue;}
if(r!=now)swap(a[now],a[r]);
for(int j=1;j<=n;j++) if(j!=now && a[j][i]) a[j]^=a[now];
pivot[i]=now;
now++;
}
}
void dfs(int d,int s){
if(!d){ans=min(ans,s);}
if(s>=ans) return;
if(pivot[d]){
bitset<N> &t=a[pivot[d]];
int x=t[n+1];
for(int i=1;i<=tot;i++) if(t[lib[i]]) x^=val[lib[i]];
dfs(d-1,s+x);
}else{
val[d]=0;dfs(d-1,s);
val[d]=1;dfs(d-1,s+1);
}
}
int main(){
freopen("a.in","r",stdin);
while(1){
scanf("%d",&n);if(!n) return 0;
for(int i=1;i<=n;i++) a[i].reset();
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
a[x][y]=1;a[y][x]=1;
}ans=n;tot=0;
for(int i=1;i<=n;i++) a[i][i]=a[i][n+1]=1;
memset(lib,0,sizeof(lib));memset(pivot,0,sizeof(pivot));
guass();
dfs(n,0);
printf("%d\n",ans);
}
return 0;
}