题解 P1312 【Mayan游戏】
只要肯去码此题,就一定能AC
所以P2482(猪国杀)也一样
剪枝原则:
1,交换两个相同颜色的块没有意义。
2,如果一种颜色的块数量为1或2,则当前局面无解。
3,因为要求字典序最小的解,所以一个块仅当左边为空时尝试左移。
本蒟蒻写了164行,最慢的点912ms。
代码(有注释):
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define N 5
#define M 7
int maxstep,chess[N][M];
int count[11];
int answer[5][3];
void init(void) //读入
{
memset(chess,0,sizeof(chess));
scanf("%d",&maxstep);
for(int i=0;i<N;i++){
int j=0,x;
scanf("%d",&x);
while(x!=0){
chess[i][j]=x;
j++;
scanf("%d",&x);
}
}
return;
}
void printchess(void) //调试用
{
for(int i=0;i<N;i++){
for(int j=0;j<M;j++)
printf("%d ",chess[i][j]);
putchar('\n');
}
return;
}
void fall(void) //清除后方块下落
{
for(int i=0;i<N;i++)
for(int j=0;j<M;j++){
if(chess[i][j]!=0)
continue;
int k;
for(k=j+1;k<M;k++)
if(chess[i][k]!=0){
chess[i][j]=chess[i][k];
chess[i][k]=0;
break;
}
if(k==M)
break;
}
return;
}
void printans(void) //输出
{
for(int i=0;i<maxstep;i++)
printf("%d %d %d\n",answer[i][0],answer[i][1],answer[i][2]);
return;
}
bool clear(void) //清除棋盘
{
bool empty[N][M];
memset(empty,0,sizeof(empty));
for(int i=0;i<3;i++)
for(int j=0;j<M;j++)
if(chess[i][j]!=0 && chess[i][j]==chess[i+1][j] && chess[i+1][j]==chess[i+2][j])
empty[i][j]=empty[i+1][j]=empty[i+2][j]=1;
for(int i=0;i<5;i++)
for(int j=0;j<N;j++)
if(chess[i][j]!=0 && chess[i][j]==chess[i][j+1] && chess[i][j+1]==chess[i][j+2])
empty[i][j]=empty[i][j+1]=empty[i][j+2]=1;
int res=0;
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
if(empty[i][j]){
chess[i][j]=0;
res=1;
}
return res;
}
bool isempty(void) // 判断棋盘是否为空
{
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
if(chess[i][j]!=0)
return 0;
return 1;
}
bool judge(void) //判断是否有一种颜色的块数量为1或2
{
memset(count,0,sizeof(count));
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
count[chess[i][j]]++;
for(int i=1;i<=10;i++)
if(count[i]==1||count[i]==2)
return 0;
return 1;
}
bool dfs(int step) //搜索
{
if(isempty()){ //发现一组解
printans();
return 1;
}
if(step>=maxstep || judge()==0) //剪枝与结束条件
return 0;
int now[N][M]; //中间状态
for(int i=0;i<N;i++) //复制棋盘
for(int j=0;j<M;j++)
now[i][j]=chess[i][j];
for(int i=0;i<N;i++)
for(int j=0;j<M;j++){ //枚举每一个方块
if(i!=N-1 && chess[i][j]!=0 && chess[i][j]!=chess[i+1][j]){
int t=chess[i][j]; chess[i][j]=chess[i+1][j]; chess[i+1][j]=t;
answer[step][0]=i; answer[step][1]=j; answer[step][2]=1;
fall();
while(clear())
fall();
if(dfs(step+1))
return 1;
} //右移
for(int k1=0;k1<N;k1++)
for(int k2=0;k2<M;k2++)
chess[k1][k2]=now[k1][k2];
if(i!=0 && chess[i][j]!=0 && chess[i-1][j]==0){
int t=chess[i][j]; chess[i][j]=chess[i-1][j]; chess[i-1][j]=t;
answer[step][0]=i; answer[step][1]=j; answer[step][2]=-1;
fall();
while(clear())
fall();
if(dfs(step+1))
return 1;
} //左移
for(int k1=0;k1<N;k1++) //复制回来
for(int k2=0;k2<M;k2++)
chess[k1][k2]=now[k1][k2];
}
return 0;
}
int main(void)
{
init();
//clear();
//fall();
//printchess();
if(dfs(0)==0)
printf("-1");
return 0;
}