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。
1 2
1 3
4 2
3 4
2 5
5 3
輸入細節:
一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。
Sample Output
3
輸出細節:
按下在燈1、燈4和燈5上面的開關。
輸出細節:
按下在燈1、燈4和燈5上面的開關。
题解
高斯消元解异或方程组。
从模拟赛只有部分分来看,我之前对高斯消元没有很好地理解:《球形空间产生器》和poj上的一道题都保证了每个未知数都有唯一解,而这道题可能出现未知元,需要dfs暴搜取最小值。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,a[50][50];
int ct,ans,s[50];
void init()
{
scanf("%d%d",&n,&m);
int i,x,y;
for(i=1;i<=n;i++) {a[i][i]=1; a[i][n+1]=1;}
for(i=1;i<=m;i++)
{scanf("%d%d",&x,&y);
a[x][y]=a[y][x]=1;
}
}
void gaos()
{
int i,j,k;
for(i=1;i<=n;i++)
{j=i;
while(j<=n&&a[j][i]==0) j++;
if(j>n) continue;
if(i!=j)
{for(k=1;k<=n+1;k++) swap(a[i][k],a[j][k]);}
for(j=1;j<=n;j++)
{if(i!=j&&a[j][i]==1)
{for(k=1;k<=n+1;k++) a[j][k]^=a[i][k];}
}
}
}
void dfs(int x)
{
if(ct>=ans) return;
if(x==0)
{if(ct<ans) ans=ct;
return ;
}
int i,num;
if(a[x][x])
{num=a[x][n+1];
for(i=x+1;i<=n;i++)
{if(a[x][i]) num^=s[i];}
s[x]=num;
if(num==1) ct++;
dfs(x-1);
if(num==1) ct--;
}
else
{s[x]=0; dfs(x-1);
s[x]=1; ct++; dfs(x-1); ct--;
}
}
int main()
{
init(); gaos();
ans=1<<30; dfs(n);
printf("%d\n",ans);
return 0;
}