题解 P1312 【Mayan游戏】
代码里shadow了I和j,见谅。
按题意安排I,j顺序。
容易发现两个非空块交换可以是左块右移或右块左移,根据题意此时右块左移无意义。
当有一个空块时,非空块的左右移都有意义。
得出剪枝,一个块的左边是非空块时不需要考虑左移。
另一个显然的剪枝,交换两个颜色相同的块没有意义。
由于我不太确定双hash的冲突率是多少,所以我选择了trie来判重。注意状态中同时包含步数和局面。通过改动trie可以得到更强的“相同局面步数不同”的剪枝。做法是在每个叶节点记录到达的最小步数。这样做的空间复杂度会略略提高,但是微乎其微。这种做法我没有尝试。
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::swap;
const int H=7,W=5,MAXN=10;
int n;
struct NODE{
bool e;
NODE* ch[11];
NODE(){memset(ch,0,sizeof(ch));e=0;}
}root;
bool in(int a[H][W],int dep){
return true;
NODE* pos=&root;
if(!pos->ch[dep]) pos->ch[dep]=new NODE();
pos=pos->ch[dep];
for(int i=0;i<H;i++) for(int j=0;j<W;j++){
if(!pos->ch[a[i][j]]) pos->ch[a[i][j]]=new NODE();
pos=pos->ch[a[i][j]];
}
if(!pos->e) return pos->e=1;
else return false;
}
struct REC{
int x,y,g;
}rec[MAXN];
bool del[H][W];
void dfs(int bc,int dep,int a[H][W]){//now dep
if(dep>n){
if(bc) return;
for(int i=1;i<=n;i++) printf("%d %d %d\n",rec[i].x,rec[i].y,rec[i].g);
exit(0);
}/*
if(dep){
printf("\ndep%d\n",dep);
for(int i=0;i<H;i++,printf("\n")) for(int j=0;j<W;j++) printf("%d ",a[i][j]);
if(a[5][2]==1&&a[5][3]==4&&a[5][4]==3) {
getchar();
}
}*/
int tmp[H][W];
memcpy(tmp,a,sizeof(tmp));
for(int j=0;j<W;j++) for(int i=H-1;i>=0;i--) for(int dd=1;dd>=-1;dd-=2) if((j+dd<W&&j+dd>=0)&&tmp[i][j]){
if(tmp[i][j]==tmp[i][j+dd]) continue;
if(dd==-1&&tmp[i][j-1]) continue;
memcpy(a,tmp,sizeof(tmp));
swap(a[i][j],a[i][j+dd]);
for(int j=0;j<W;j++) for(int i=H-1;i>=0;i--){
if(a[i][j]) for(int ni=i;ni+1<H&&!a[ni+1][j];ni++) a[ni+1][j]=a[ni][j],a[ni][j]=0;
}
int cnt=0,tcnt=0;
while(1){
memset(del,0,sizeof(del));
for(int i=0;i<H;i++) {
int j=0;
while(j<W){
int t;
for(t=j;t+1<W;){
if(a[i][j]&&a[i][j]==a[i][t+1]) t++;
else break;
}
if(t-j+1>=3) for(int k=j;k<=t;k++) del[i][k]=1;
j=t+1;
}
}
for(int j=0;j<W;j++) {
int i=0;
while(i<H){
int t;
for(t=i;t+1<H;){
if(a[i][j]&&a[i][j]==a[t+1][j]) t++;
else break;
}
if(t-i+1>=3) for(int k=i;k<=t;k++) del[k][j]=1;
i=t+1;
}
}
for(int i=0;i<H;i++) for(int j=0;j<W;j++) cnt+=del[i][j],a[i][j]=del[i][j]?0:a[i][j];
if(!cnt) break;
else tcnt+=cnt,cnt=0;
for(int j=0;j<W;j++) for(int i=H-1;i>=0;i--){
if(a[i][j]) for(int ni=i;ni+1<H&&!a[ni+1][j];ni++) a[ni+1][j]=a[ni][j],a[ni][j]=0;
}
}
rec[dep].x=j,rec[dep].y=H-i-1,rec[dep].g=dd;
if(in(a,dep)) dfs(bc-tcnt,dep+1,a);
}
}
int a[H][W];
int main(){
scanf("%d",&n);
int tot=0;
for(int j=0;j<5;j++){
int t,i=H-1;
scanf("%d",&t);
while(t){
a[i][j]=t;
scanf("%d",&t);
tot++;
i--;
}
}
in(a,0);
dfs(tot,1,a);
printf("-1");
}