1. 程式人生 > >panel(NOIP模擬賽Round 4)

panel(NOIP模擬賽Round 4)

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)