poj2488题解
题意
骑士(类似于中国象棋里的马)从任意起点出发,遍历n*m的棋盘上的每一个格子,在任意终点结束,输出最小字典序遍历道路。
笺释
按照字典序遍历起点,然后进入dfs搜索。
按照下列1-8的顺序移动就是最小字典序
int movm[9]={0,-2,-2,-1,-1,1,1,2,2};
int movn[9]={0,-1,1,-2,2,-2,2,-1,1};
也就是按照向左上,左下,右上,右下移动。
记录路径用一个maps[num(当前步数)]数组即可,不用写递归记录。
本来半个小时就写完了,但是WA了很久,自己一直找不到错,取discuss里拿到了所有有效数据和AC代码对拍也都没错,最后发现是在遍历起点的代码
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
memset(maps,0,sizeof(maps));
memset(vis,0,sizeof(vis));
maps[1][0]=j;
maps[1][1]=i;
vis[j][i]=1;
dfs(j,i,1);
if(flag==1)
{
break;
}
}
if(flag==1)
{
break;
}
}
dfs(j,i,1)一直写成了dfs(i,j,1),但是一般来说起点都是A1所以这里是能过很多样例的(我感觉是全部有效数据),不知道poj用什么样例卡掉的,不过很厉害。
完整代码
#include<cstdio>
#include<cstring>
#define MAXN 28
using namespace std;
int movm[9]={0,-2,-2,-1,-1,1,1,2,2};
int movn[9]={0,-1,1,-2,2,-2,2,-1,1};
int vis[MAXN][MAXN];
int maps[MAXN*MAXN][2];
int flag;
char alp[27]={'\0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
int n,m;
int t;
void print()
{
for(int i=1;i<=n*m;i++)
{
printf("%c%d",alp[maps[i][1]],maps[i][0]);
}
printf("\n");
printf("\n");
}
bool legal(int newn,int newm)
{
if(!(newn>=1&&newn<=n))
{
return false;
}
if(!(newm>=1&&newm<=m))
{
return false;
}
return true;
}
void dfs(int temn,int temm,int num)
{
if(num==n*m)
{
flag=1;
print();
return;
}
for(int i=1;i<=8;i++)
{
int newn=temn+movn[i];
int newm=temm+movm[i];
if(legal(newn,newm))
{
if(!vis[newn][newm])
{
vis[newn][newm]=1;
maps[num+1][0]=newn;
maps[num+1][1]=newm;
dfs(newn,newm,num+1);
if(flag)
{
return;
}
vis[newn][newm]=0;
maps[num+1][0]=0;
maps[num+1][1]=0;
}
}
}
}
int main()
{
//freopen("c:\\output.txt","w",stdout);
int c=1;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
printf("Scenario #%d:\n",c++);
flag=0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
memset(maps,0,sizeof(maps));
memset(vis,0,sizeof(vis));
maps[1][0]=j;
maps[1][1]=i;
vis[j][i]=1;
dfs(j,i,1);
if(flag==1)
{
break;
}
}
if(flag==1)
{
break;
}
}
if(n*m>26)
{
flag=0;
}
if(flag==0)
{
printf("impossible\n");
printf("\n");
}
}
}