poj2488

参考 http://user.qzone.qq.com/289065406/blog/1303350143


一步一步地写出结果。
第一步是如何判断能否遍历整个棋盘。对于输出路径先不予考虑。由于题目要求字典序遍历,因此每一步,按照从左到右,从上到下的顺序试,第一次得到的必然是字典序。
step函数就是这个作用。

然后是一个递归函数,函数结束的条件是走的步数等于棋盘的格子数。vis用于记录每个格子是否到达过。for循环就是使走的下一步按照从左到右,从上到下的顺序走。


    for(int k=1;k<=8;++k){
        step(i,j,k);
        int ii=x,jj=y;
        if(!vis[ii][jj]&&ii>=1&&jj>=1&&ii<=p&&jj<=q)
            if(dfs(ii,jj,s+1))return true; 
    }

当第k步执行到if时,先判断这个格子是否走过,再看是否越界。然后就看它的下一步是否能够成功。如果能成功,第k部就返回true,使第k步的上一步(k-1)继续返回true。这就是递归过程。如果能执行到

    vis[i][j]=false;
    return false;

就说明这一步的下一步不能成功遍历,那么相应的这一步也就不能成功遍历。那么把这一步走过的记号(vis)变成没有访问过,回到上一步继续试。在接下来的主函数里面,判断是否能够成功。
前面两个if用于缩小范围。可以看到每个impossible后面都有一个数字作记号,这样在输出impossible 的时候可以知道到底是哪个if使它输出impossible的。
当然,这个主函数是有bug的,如果你第一次输入4 3,第二次再输入4 3,那么第一次会输出possible,第二次会输出impossible。还有其他的各种各样的bug。反正是一个基本的程序,只要能完成基本的功能,其他的bug下面再慢慢修补。

#include<iostream>
using namespace std;
  

int vis[26][26];
int x,y;
int p,q;
 
int step(int i,int j,int k){
    switch(k){
        case 1:{x=i-1;y=j-2;break;}
        case 2:{x=i+1;y=j-2;break;}
        case 3:{x=i-2;y=j-1;break;}
        case 4:{x=i+2;y=j-1;break;}
        case 5:{x=i-2;y=j+1;break;}
        case 6:{x=i+2;y=j+1;break;}
        case 7:{x=i-1;y=j+2;break;}
        case 8:{x=i+1;y=j+2;break;}
    }
}
  
int dfs(int i,int j,int s){
    vis[i][j]=true;
    if(s==p*q)return true;
     
    for(int k=1;k<=8;++k){
        step(i,j,k);
        int ii=x,jj=y;
        if(!vis[ii][jj]&&ii>=1&&jj>=1&&ii<=p&&jj<=q)
            if(dfs(ii,jj,s+1))return true; 
    }
    vis[i][j]=false;
    return false;
}
 
int main(){
    int n;
    cin>>n;
    for(;n;n--){
        cin>>p>>q;
        if(p==1||q==1){
            cout<<"Scenario #"<<n<<':'<<endl;
            cout<<"impossible"<<endl;cout<<"1"<<endl;
	    continue;
        }
        if(p*q>26){
            cout<<"Scenario #"<<n<<':'<<endl;
            cout<<"impossible2"<<endl;
	    continue;
        }
        if(dfs(1,1,1)){
            cout<<"Scenario #"<<n<<':'<<endl;
            cout<<"possible"<<endl;
        }
        else {
            cout<<"Scenario #"<<n<<':'<<endl;
            cout<<"impossible3"<<endl;
        }
    }
}

下面一步就是记录每步走过的地方并且输出。然后就是修补一些bug。
对于上面说的4 3的bug,加上memset函数就行了。
对于走过的路径的记录是在dfs 函数里面实现的。每走一步就记录一次,如果这一步没有成功,就会返回上一步,然后再向下的时候就会把错误的值给覆盖掉。

#include<iostream>
#include<string.h>
using namespace std;
  
int row[26];
char col[26];
int vis[26][26];
int x,y;
int p,q;
 
int step(int i,int j,int k){
    switch(k){
        case 1:{x=i-1;y=j-2;break;}
        case 2:{x=i+1;y=j-2;break;}
        case 3:{x=i-2;y=j-1;break;}
        case 4:{x=i+2;y=j-1;break;}
        case 5:{x=i-2;y=j+1;break;}
        case 6:{x=i+2;y=j+1;break;}
        case 7:{x=i-1;y=j+2;break;}
        case 8:{x=i+1;y=j+2;break;}
    }
}
  
int dfs(int i,int j,int s){
    vis[i][j]=true;
    row[s]=i;
    col[s]='A'+j-1;
    if(s==p*q)return true;
     
    for(int k=1;k<=8;++k){
        step(i,j,k);
        int ii=x,jj=y;
        if(!vis[ii][jj]&&ii>=1&&jj>=1&&ii<=p&&jj<=q)
            if(dfs(ii,jj,s+1))return true; 
    }
    vis[i][j]=false;
    return false;
}
 
int main(){
    int n;
    cin>>n;
    for(int	z=1;z<=n;z++){
        cin>>p>>q;
        memset(vis,false,sizeof(vis));
        if(p*q>26){
        	cout<<"Scenario #"<<z<<':'<<endl;
            cout<<"impossible"<<endl;
            continue;
        }
        if(dfs(1,1,1)){
            cout<<"Scenario #"<<z<<':'<<endl;
            for(int i=1;i<=p*q;++i){
            	cout<<col[i]<<row[i];
            }
            cout<<endl;
        }
        else {
            cout<<"Scenario #"<<z<<':'<<endl;
            cout<<"impossible"<<endl;
        }
        cout<<endl;
    }
}

这道题,据说是水题……可是对我来说,还是有点难度。毕竟对于递归调用还是很不熟练。我把我做这道题的时候的步骤简单的写了下来。其中参考了别人的日志,但是我是在看了一遍别人的东西以后,在自己写的过程中绝对不看别人的东西。希望能够有些长进。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值