「BZOJ1770」[Usaco2009 Nov] lights 燈
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上面的開關。
题解
目测直接搜索就可以了。。。
按照人偶师的做法。。。meet in the middle
正确姿势是消元完爆搜自由源
折半搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<set> #include<map> #define inf 1000000000 #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } bool flag; int n,m,cnt,mn=inf; int a[40]; ll ed,p[40],bin[40]; map<ll,int> b; void dfs(int x,ll now,int used) { if(x==cnt+1) { if(now==ed)mn=min(used,mn); if(!flag) { int t=b[now]; if(!t||t>used)b[now]=used; } else { int t=b[ed-now]; if(!t)return; mn=min(t+used,mn); } return; } dfs(x+1,now,used); dfs(x+1,now^p[x],used+1); } int main() { bin[1]=1;for(int i=2;i<40;i++)bin[i]=bin[i-1]<<1; n=read();m=read(); ed=bin[n+1]-1; for(int i=1;i<=m;i++) { int a=read(),b=read(); p[a]+=bin[b];p[b]+=bin[a]; } for(int i=1;i<=n;i++)p[i]+=bin[i]; cnt=n/2;dfs(1,0,0); flag=1; cnt=n;dfs(n/2+1,0,0); printf("%d\n",mn); return 0; } |
高斯消元
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #define inf 1000000000 #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,tot; int mn=inf; int f[45][45],ans[45]; void gauss() { for(int i=1;i<=n;i++) { int j=i; while(j<=n&&!f[j][i])j++; if(j>n)continue; if(i!=j)for(int k=1;k<=n+1;k++)swap(f[i][k],f[j][k]); for(int j=1;j<=n;j++) if(i!=j&&f[j][i]) for(int k=1;k<=n+1;k++) f[j][k]^=f[i][k]; } } void dfs(int now) { if(tot>=mn)return; if(!now) { mn=min(mn,tot); return; } if(f[now][now]) { int t=f[now][n+1]; for(int i=now+1;i<=n;i++) if(f[now][i])t^=ans[i]; ans[now]=t; if(t)tot++; dfs(now-1); if(t)tot--; } else { ans[now]=0;dfs(now-1); ans[now]=1;tot++;dfs(now-1);tot--; } } int main() { n=read();m=read(); for(int i=1;i<=n;i++) f[i][i]=1,f[i][n+1]=1; for(int i=1;i<=m;i++) { int x=read(),y=read(); f[x][y]=f[y][x]=1; } gauss();dfs(n); printf("%d\n",mn); return 0; } |
请问meet in the middle里那个dfs函数里now和used,还有外面的bin分别指什么( ̄▽ ̄)
黄学长放的这两份代码思路上有什么不同嘛?
已更正