高斯消元解xor方程组...暴搜自由元+最优性剪枝
-----------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
const int maxn = 49;
int N, Id[maxn], State[maxn], ans = maxn;
bitset<maxn> mat[maxn];
void Init() {
int m;
scanf("%d%d", &N, &m);
for(int i = 0; i < N; i++) {
mat[i].reset();
mat[i][i] = mat[i][N] = 1;
}
while(m--) {
int u, v;
scanf("%d%d", &u, &v); u--; v--;
mat[u][v] = mat[v][u] = 1;
}
memset(Id, -1, sizeof Id);
}
void Work() {
int k = 0;
for(int i = 0; i < N; i++) {
for(int j = k; j < N; j++) if(mat[j][i]) {
if(j != k)
swap(mat[j], mat[k]);
break;
}
if(mat[k][i]) {
for(int j = k; ++j < N; )
if(mat[j][i]) mat[j] ^= mat[k];
Id[i] = k++;
}
}
}
void Dfs(int x, int sum) {
if(sum >= ans)
return;
if(x < 0) {
ans = sum; return;
}
if(~Id[x]) {
State[x] = mat[Id[x]][N];
for(int i = x; ++i < N; )
if(mat[Id[x]][i]) State[x] ^= State[i];
Dfs(x - 1, sum + State[x]);
} else {
for(int i = 0; i < 2; i++)
Dfs(x - 1, sum + (State[x] = i));
}
}
int main() {
Init();
Work();
Dfs(N - 1, 0);
printf("%d\n", ans);
return 0;
}
-----------------------------------------------------------------------------
1770: [Usaco2009 Nov]lights 燈
Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 545 Solved: 260
[Submit][Status][Discuss]
Description
貝希和她的閨密們在她們的牛棚中玩遊戲。但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了。貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N。這些燈被置於一個非常複雜的網絡之中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。 每盞燈上面都帶有一個開關。當按下某一盞燈的開關的時候,這盞燈本身,還有所有有邊連向這盞燈的燈的狀態都會被改變。狀態改變指的是:當一盞燈是開著的時候,這盞燈被關掉;當一盞燈是關著的時候,這盞燈被打開。 問最少要按下多少個開關,才能把所有的燈都給重新打開。 數據保證至少有一種按開關的方案,使得所有的燈都被重新打開。
Input
*第一行:兩個空格隔開的整數:N和M。
*第二到第M+1行:每一行有兩個由空格隔開的整數,表示兩盞燈被一條無向邊連接在一起。 沒有一條邊會出現兩次。
Output
第一行:一個單獨的整數,表示要把所有的燈都打開時,最少需要按下的開關的數目。
Sample Input
5 6
1 2
1 3
4 2
3 4
2 5
5 3
輸入細節:
一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。
Sample Output
3
輸出細節:
按下在燈1、燈4和燈5上面的開關。