好吧,,这道题。。本来以为挺难的。打了个暴力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); }
时间: 2024-10-29 12:41:49