首页 > 代码库 > panel(NOIP模拟赛Round 4)

panel(NOIP模拟赛Round 4)

原题传送门

好吧,,这道题。。本来以为挺难的。打了个暴力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)