题目:https://www.luogu.org/problemnew/show/P1312
还是不擅长这种题,所以参考了一下TJ;
其实也很好搜,按字典序,先搜右移,再搜左移;
不交换相同颜色的两个格子,因为浪费;
左移就不交换了,避免重复,只有左边为空时左移;
写个处理下落的 fall 函数,再写个处理消格子的 refresh 函数(其中用到了 fall ),就可以方便地搜索了!
我存的是行和列,所以和坐标正好相反,一定要注意字典序的处理!
优美。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,mp[10][10][10],ansx[10],ansy[10],ansm[10]; bool vis[10][10]; void fall(int s) { for(int j=1,sz;j<=5;j++) { sz=0; for(int i=1;i<=7;i++) if(mp[s][i][j])mp[s][++sz][j]=mp[s][i][j]; while(sz<7)mp[s][++sz][j]=0;// } } void refresh(int s) { bool fl=0; while(1) { fl=0; fall(s); for(int i=1;i<=7;i++) for(int j=1;j<=5;j++) { if(!mp[s][i][j])continue;// if(i<=5&&mp[s][i][j]==mp[s][i+1][j]&&mp[s][i][j]==mp[s][i+2][j]) { fl=1; vis[i][j]=vis[i+1][j]=vis[i+2][j]=1; } if(j<=3&&mp[s][i][j]==mp[s][i][j+1]&&mp[s][i][j]==mp[s][i][j+2]) { fl=1; vis[i][j]=vis[i][j+1]=vis[i][j+2]=1; } } if(!fl)break; for(int i=1;i<=7;i++) for(int j=1;j<=5;j++) if(vis[i][j])mp[s][i][j]=0,vis[i][j]=0; } } bool dfs(int s) { for(int i=1;i<=7;i++) for(int j=1;j<=5;j++)mp[s][i][j]=mp[s-1][i][j]; refresh(s); if(s>n) { for(int j=1;j<=5;j++) if(mp[s][1][j])return 0; return 1; } for(int j=1;j<=5;j++)//字典序! for(int i=1;i<=7;i++) if(mp[s][i][j]) { if(j<5&&mp[s][i][j]!=mp[s][i][j+1])//1 { ansx[s]=i; ansy[s]=j; ansm[s]=1; swap(mp[s][i][j],mp[s][i][j+1]); if(dfs(s+1))return 1; swap(mp[s][i][j],mp[s][i][j+1]); } if(j>1&&!mp[s][i][j-1])//-1 { ansx[s]=i; ansy[s]=j; ansm[s]=-1; swap(mp[s][i][j],mp[s][i][j-1]); if(dfs(s+1))return 1; swap(mp[s][i][j],mp[s][i][j-1]); } } return 0; } int main() { scanf("%d",&n); for(int j=1;j<=5;j++) for(int i=1,x;i<=8;i++) { scanf("%d",&x); if(!x)break; mp[0][i][j]=x; } if(dfs(1))//1 { for(int i=1;i<=n;i++) printf("%d %d %d\n",ansy[i]-1,ansx[i]-1,ansm[i]);//坐标! } else printf("-1\n"); return 0; }
洛谷 P1312 [ NOIP 2011 ] Mayan游戏 —— 搜索+模拟
原文:https://www.cnblogs.com/Zinn/p/9403666.html