panel(NOIP模擬賽Round 4)
阿新 • • 發佈:2017-05-26
else ane log 情況 target 告訴 open panel 模擬
原題傳送門
好吧,,這道題。。本來以為挺難的。打了個暴力bfs+hash(期望得分30,實際得分30)
奇特的是,這道題如果不用hash(期望得分20,實際得分100),好吧數據實在是太水了(不會T嗎?)
然後我們尋找正解
在此膜一下巨神學弟clz
著名的clz告訴我們,我們只需要暴力枚舉第一行的情況,然後可以直接O(n^7m)得出結果??
因為我們知道,假設第一行的情況是確定的,並且我們已經遞歸到了第二行的第i個按鈕。
那麽panel[1][i-1]若是不亮的,那麽我們必須要按這個按鈕,因為除了這種辦法沒有辦法使panel[1][i-1]變亮。
後n-2行同理
雖然跑的比標程慢,但是好理解多啦!!
順便提一下標程的解法:
標程的解法其實差不多,不過在暴力枚舉第一行的同時還暴力枚舉了第一列,這樣做的時候判斷次數減少,所以更快
復雜度玄學。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; bool block[10][10]; bool now[10][10]; int ans,n,m,t; char ch; int sum; /*inline void fan(int x,int y) { for(int i=x-1;i<=x+1;i++) for(int j=y-1;j<=y+1;j++) now[i][j]^=1; }*/ inline void fan(int x,int y) { now[x-1][y-1]^=1;now[x-1][y]^=1;now[x-1][y+1]^=1; now[x][y-1]^=1;now[x][y]^=1;now[x][y+1]^=1; now[x+1][y-1]^=1;now[x+1][y]^=1;now[x+1][y+1]^=1; } void dfs(int num){ if(num>n) { for(int i=1;i<=m;i++) { if(!now[n][i])return; } ans=ans<sum?ans:sum;return; } fan(num,1);sum++; int s; s=0; for(int i=1;i<m;i++) if(!now[num-1][i])fan(num,i+1),sum++,s|=(1<<i); if(now[num-1][m])dfs(num+1); for(int i=1;i<m;i++) if((s>>i)&1)fan(num,i+1),sum--; fan(num,1);sum--; s=0; for(int i=1;i<m;i++) if(!now[num-1][i])fan(num,i+1),sum++,s|=(1<<i); if(now[num-1][m])dfs(num+1); for(int i=1;i<m;i++) if((s>>i)&1)fan(num,i+1),sum--; } int main(){ // freopen("panel.in","r",stdin); // freopen("panel.out","w",stdout); scanf("%d",&t); for(int i=1;i<=t;i++) { ans=999; scanf("%d%d",&n,&m); for(int j=1;j<=n;j++) for(int k=1;k<=m;k++) { ch=getchar(); if(ch==‘*‘) block[j][k]=1; else if(ch==‘.‘) block[j][k]=0; else --k; } for(int s=0;s<(1<<m);s++) { sum=0; for(int j=1;j<=n;j++) for(int k=1;k<=m;k++) now[j][k]=block[j][k]; for(int j=0;j<m;j++) { if((s>>j)&1) fan(1,j+1),sum++; } dfs(2); } if(ans==999)puts("-1"); else printf("%d\n",ans); } // fclose(stdin); // fclose(stdout); }
panel(NOIP模擬賽Round 4)