bzoj2466
高斯消元+搜索
很明显每个开关只能按一次,那么我们可以想到高斯消元,其实就是解异或方程组,但是最后会有一些自由元,也就是有x+y=z,x+y=z这种一样的方程就会产生自由元,那么我们爆搜自由元取值,每次把自由元回带入方程,因为形如x+y=z这样的方程就需要回带,然后就解出一组解,取最小值即可。这当然不是正解,100怎么能爆搜,正解是树形dp。
#include<bits/stdc++.h> using namespace std; const int Maxlen = 10000010, N = 110; int n, ans; int a[N][N], mark[N], val[N]; namespace IO { char buf[Maxlen], *C = buf; int Len; inline void read_in() { Len = fread(C, 1, Maxlen, stdin); buf[Len] = '\0'; } inline void fread(int &x) { x = 0; int f = 1; while (*C < '0' || '9' < *C) { if(*C == '-') f = -1; ++C; } while ('0' <= *C && *C <= '9') x = (x << 1) + (x << 3) + *C - '0', ++C; x *= f; } inline void read(int &x) { x = 0; int f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + c - '0'; c = getchar(); } x *= f; } } using namespace IO; void dfs(int d, int tot) { if(tot >= ans) return; if(d == 0) { ans = min(ans, tot); return; } if(mark[d]) { int x = a[d][n + 1]; for(int i = 1; i <= n; ++i) if(!mark[i] && a[d][i]) x ^= val[i]; dfs(d - 1, tot + x); } else { val[d] = 0; dfs(d - 1, tot); val[d] = 1; dfs(d - 1, tot + 1); } } void gauss() { ans = n; for(int now = 1; now <= n; ++now) { int pos = now; while(!a[pos][now] && pos <= n) ++pos; if(pos == n + 1) continue; swap(a[pos], a[now]); for(int i = 1; i <= n; ++i) if(a[i][now] && i != now) for(int j = 1; j <= n + 1; ++j) a[i][j] ^= a[now][j]; mark[now] = 1; } dfs(n, 0); printf("%d\n", ans); } int main() { while(1) { read(n); if(n == 0) break; memset(val, 0, sizeof(val)); memset(a, 0, sizeof(a)); memset(mark, 0, sizeof(mark)); for(int i = 1; i <= n; ++i) { a[i][i] = 1; a[i][n + 1] = 1; } for(int i = 1; i < n; ++i) { int u, v; read(u); read(v); a[u][v] = a[v][u] = 1; } gauss(); } return 0; }