poj2488

来源:互联网 发布:java未安装成功 编辑:程序博客网 时间:2024/06/04 19:42
参考 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(intz=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;    }}

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