搜索题【1】
题目描述
传送门
题解
对于左右两个相邻非空块,肯定是左边右移而不是右边左移,
那什么时候要枚举左移呢,很显是左边为空块。
这是一个非常重要的剪枝,表示一开始打错,被TLE暴虐……
code
#include <bits/stdc++.h>
#define re register int
using namespace std;
int a[10][10],ans[10][5],vis[10][10],col[11],n,N;
inline int clr(){
for(re i=9;i;--i)for(re j=9;j;--j)vis[i][j]=1;
int res=0,l,r,u,d,x,y,t;
bool f=0;
for(re i=1;i<=5;++i)for(re j=1;j<=7;++j)
if(a[i][j]&&((j>=2&&a[i][j-1])||j==1)){
l=r=i,d=u=j;
while(l>=2&&a[l-1][j]==a[i][j])--l;
while(r<=4&&a[r+1][j]==a[i][j])r++;
while(d>=2&&a[i][d-1]==a[i][j])d--;
while(u<=6&&a[i][u+1]==a[i][j])u++;
if(r-l>=2)for(re k=l;k<=r;k++)vis[k][j]=0;
if(u-d>=2)for(re k=d;k<=u;k++)vis[i][k]=0;
}
for(re i=1;i<=5;++i)for(re j=1;j<=7;++j)
if(!vis[i][j])res++,a[i][j]=0;
for(int i=1,j;i<=5;++i){
for(j=1;j<=7;++j)if(!a[i][j]) break;
if(j==8) continue;x=j;
for( ;j<=7;++j)if(a[i][j]) break;
if(j==8) continue;y=j-1,t=0;
for(j=x;j<=7;j++){
if(!a[i][y+(++t)]||a[i][j]) break;
a[i][j]=a[i][y+t],a[i][y+t]=0,f=1;
}
}
if(f)res+=clr();return res;
}
inline bool check(){
int c[11];
for(re i=10;i;--i)c[i]=0;
for(re i=5;i;--i)for(re j=7;j;--j)c[a[i][j]]++;
for(int i=1;i<=N;++i)if(c[i]>=1&&c[i]<=2)return 0;
return 1;
}
inline void dfs(int step,int last){
if(!check()) return;
if(step>=n+1){
if(!last){
for(int i=1;i<=n;i++)
printf("%d %d %d\n",ans[i][1]-1,ans[i][2]-1,ans[i][3]);
exit(0);
}
return;
}
int t[10][10];
for(re i=5;i;--i)for(re j=7;j;--j)t[i][j]=a[i][j];
for(re i=1;i<=5;++i)for(re j=1;j<=7;++j)if(a[i][j]){
if(i<=4&&a[i][j]!=a[i+1][j]){
swap(a[i][j],a[i+1][j]),ans[step][1]=i,ans[step][2]=j,ans[step][3]=1;
dfs(step+1,last-clr());
for(re p=5;p;--p)for(re q=7;q;--q)a[p][q]=t[p][q];
}
if(i>=2&&!a[i-1][j]){
swap(a[i][j],a[i-1][j]),ans[step][1]=i,ans[step][2]=j,ans[step][3]=-1;
dfs(step+1,last-clr());
for(re p=5;p;--p)for(re q=7;q;--q)a[p][q]=t[p][q];
}
}
}
int main(){
int cnt=0;scanf("%d",&n);
for(int i=1,j,k=0;i<=5;i++,k=0){
scanf("%d",&j);
while(j){
a[i][++k]=j,++cnt;
if(!col[j])col[j]=1,++N;
scanf("%d",&j);
}
}
dfs(1,cnt);printf("-1");return 0;
}