JZOJ 1321. 灯
Description
貝希和她的閨密們?cè)谒齻兊呐E镏型嬗螒颉5翘觳粡娜嗽?#xff0c;突然,牛棚的電源跳閘了,所有的燈都被關(guān)閉了。貝希是一個(gè)很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續(xù)快樂地跟她的閨密們繼續(xù)玩游戲!
牛棚中一共有N(1 <= N <= 35)盞燈,編號(hào)為1到N。這些燈被置于一個(gè)非常復(fù)雜的網(wǎng)絡(luò)之中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。
每盞燈上面都帶有一個(gè)開關(guān)。當(dāng)按下某一盞燈的開關(guān)的時(shí)候,這盞燈本身,還有所有有邊連向這盞燈的燈的狀態(tài)都會(huì)被改變。狀態(tài)改變指的是:當(dāng)一盞燈是開著的時(shí)候,這盞燈被關(guān)掉;當(dāng)一盞燈是關(guān)著的時(shí)候,這盞燈被打開。
問最少要按下多少個(gè)開關(guān),才能把所有的燈都給重新打開。
數(shù)據(jù)保證至少有一種按開關(guān)的方案,使得所有的燈都被重新打開。
Input
第一行:兩個(gè)空格隔開的整數(shù):N和M。
第二到第M+1行:每一行有兩個(gè)由空格隔開的整數(shù),表示兩盞燈被一條無向邊連接在一起。沒有一條邊會(huì)出現(xiàn)兩次。
Output
第一行:一個(gè)單獨(dú)的整數(shù),表示要把所有的燈都打開時(shí),最少需要按下的開關(guān)的數(shù)目。
Sample Input
5 6
1 2
1 3
4 2
3 4
2 5
5 3
Sample Output
3
Data Constraint
Hint
【樣例說明】
一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。按下在燈1、燈4和燈5上面的開關(guān)。
Solution
這道題看上去無從下手, N≤35 的范圍令人有些不知所措。
事實(shí)上這道題的解法十分巧妙,用到了 折半搜索 的巧法。
分別搜索 217 和 218 兩部分,記錄其中一部分的答案,用哈希表儲(chǔ)存。
處理另一部分時(shí)從哈希表中查找,異或出答案,相加即可。
這樣的時(shí)間復(fù)雜度折半為 2N2 ,可以通過本題。
詳細(xì)代碼見下面:(C++選手可以使用 STL 的 Map 庫代替哈希,代碼為注釋部分,簡單卻較慢)
據(jù)說 這題可以用高斯消元來做,一盞燈與周圍燈的異或值為 1 表示亮,列出 N 個(gè)方程解之。
Code
#include<cstdio> //#include<map> using namespace std; const int N=36,mo=1234321; //map<long long,int>mp; int n,m,m1,m2,ans=N; int a[N][N]; long long p[N],f[N],g[mo],h[mo]; bool bz[N]; inline int read() {int X=0,w=1; char ch=0;while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();return X*w; } inline int min(int a,int b) {return a<b?a:b; } inline int hash(long long x) {int y=x%mo;while(h[y] && h[y]!=x) y=(y+1)%mo;return y; } inline void dfs1(int x) {if(x>m1){long long num=0;int s=1;for(int i=1;i<=m1;i++)if(bz[i]) num^=f[i],s++;int k=hash(num);if(!h[k]) h[k]=num,g[k]=s; elseg[k]=min(g[k],s);/*if(!mp[num]) mp[num]=s; elsemp[num]=min(mp[num],s);*/return;}bz[x]=true;dfs1(x+1);bz[x]=false;dfs1(x+1); } inline void dfs2(int x) {if(x>m2){long long num=0;int s=-1;for(int i=m1+1;i<=m2;i++)if(bz[i]) num^=f[i],s++;int k=hash(p[n]-1-num);if(h[k]) ans=min(ans,g[k]+s);//if(mp[p[n]-1-num]) ans=min(ans,mp[p[n]-1-num]+s);return;}bz[x]=true;dfs2(x+1);bz[x]=false;dfs2(x+1); } int main() {freopen("1!.in","r",stdin);n=read(),m=read();for(int i=p[0]=1;i<=n;i++) p[i]=p[i-1]<<1;for(int i=1;i<=m;i++){int x=read(),y=read();a[x][++a[x][0]]=y;a[y][++a[y][0]]=x;}for(int i=1;i<=n;i++){f[i]=p[i-1];for(int j=1;j<=a[i][0];j++) f[i]+=p[a[i][j]-1];}m1=min(N>>1,m2=n);//mp[0]=1;dfs1(1);dfs2(m1+1);printf("%d",ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 1321. 灯的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 1319. 邮递员
- 下一篇: JZOJ 1322. 硬币游戏