经典搜索题

来源:互联网 发布:淘宝网注册企业店铺 编辑:程序博客网 时间:2024/06/10 15:04

前言

最近做了好多搜索题,整理一发比较好的题目,搜索题比赛虽然不怎么考,但是可以提升代码

能力,还是骗分必备(手动滑稽),不多说,步入正题

A Knight’s Journey

原题

POJ - 2488 http://poj.org/problem?id=2488

题意

国际象棋中的马走”日”字格,问能否找到一种方案使得马到达棋盘每一个点,输出字典序最

小的路径

题解

具体思路

暴力dfs,对于每一个点向8个方向扩展路径,并用flag[]数组标记已到达的点,难点在于字典

序最小的路径,我们可以改变搜索的顺序,先搜索字典序小的走法来达到这一目的.

AC代码

#include<cstdio>#include<cstring>using namespace std;const int MAXN=30;bool flag[MAXN][MAXN],b;int all,tmp,cnt;int p,q;int ans1[MAXN],ans2[MAXN];void dfs(int i,int j) {    if(flag[i][j]==1) return ;    cnt++;    ans1[cnt]=i,ans2[cnt]=j;    flag[i][j]=1;    if(cnt==all) {        b=1;        return ;    }    if(i-2>0&&j-1>0&&b==0) {        dfs(i-2,j-1);    }    if(i-2>0&&j+1<p+1&&b==0) {        dfs(i-2,j+1);    }    if(i-1>0&&j-2>0&&b==0) {        dfs(i-1,j-2);    }    if(i-1>0&&j+2<p+1&&b==0) {        dfs(i-1,j+2);    }    if(i+1<q+1&&j-2>0&&b==0) {        dfs(i+1,j-2);    }    if(i+1<q+1&&j+2<p+1&&b==0) {        dfs(i+1,j+2);    }    if(i+2<q+1&&j-1>0&&b==0) {        dfs(i+2,j-1);    }    if(i+2<q+1&&j+1<p+1&&b==0) {        dfs(i+2,j+1);    }    flag[i][j]=0;    cnt--;}int main() {    int n,ca=0;    scanf("%d",&n);    while(n--) {        memset(flag,0,sizeof(flag));        memset(ans1,0,sizeof(ans1));        memset(ans2,0,sizeof(ans2));        b=0,tmp=0,cnt=0;        scanf("%d %d",&p,&q);        printf("Scenario #%d:\n",++ca);        all=p*q;        dfs(1,1);        if(b) {            for(int i=1; i<=all; i++) {                char c=ans1[i]+64;                printf("%c%d",c,ans2[i]);            }            puts("");            puts("");        } else {            puts("impossible");            puts("");        }    }}

Catch That Cow

原题

POJ - 3278 http://poj.org/problem?id=3278

题意

一个人初始在N位置,要追一头在K位置的不动的奶牛,他有两种走法,第一种向前走一步或

向后走一步,第二种传送到当前位置*2的地方,问最少需要走几步能追上奶牛.

题解

具体思路

bfs,用队列维护人的状态:当前的位置和已走的步数,但只这样子会TLE,我们考虑加一些剪

枝,当人的当前位置已经大于奶牛位置时,向前走和传送到两倍位置都是没有意义的,向后走

一步是当前的最优解,这就是”最优性剪枝”

AC代码

#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;typedef long long int LL;const int INF=1e9;typedef pair <int,int> P;bool flag[300010];int n,k;int main() {    while(~scanf("%d %d",&n,&k)) {        int ans=0;        memset(flag,0,sizeof(flag));        queue <P> q;        q.push(make_pair(n,0));        flag[n]=1;        while(!q.empty()) {            P tmp=q.front();            flag[tmp.first]=1;            q.pop();            if(tmp.first==k) {                ans=tmp.second;                break;            }             else {                if(tmp.first<k&&flag[2*tmp.first]==0) {                    q.push(make_pair(2*tmp.first,tmp.second+1));                }                if(tmp.first<k&&flag[tmp.first+1]==0) {                    q.push(make_pair(tmp.first+1,tmp.second+1));                }                if(tmp.first>0&&flag[tmp.first-1]==0) {                    q.push(make_pair(tmp.first-1,tmp.second+1));                }            }        }        printf("%d\n",ans);    }}

Prime Path

原题

POJ - 3126 http://poj.org/problem?id=3126

题意

给出一个四位质数,让你每次改变质数的一个数字,且改变后仍为质数,使其最终变为另一个

给定质数,问最小改变次数,若方案不存在,输出Impossible

题解

具体思路

数位bfs,重复到达一个数是没有意义的,用flag[]数组判重,之后对于每一个数,枚举四个位

置从0-9(注意千位不能有0) ,用队列维护是素数的状态,当搜到目标状态时跳出,如果搜到

队列为空还没有出答案,肯定不存在,输出Impossible

AC代码

#include<cstdio>#include<queue>#include<cstring>using namespace std;const int MAXN=30010;typedef pair<int,int> P;bool flag[MAXN];bool is_prime(int num){    for(int i=2;i*i<=num;i++){        if(num%i==0) return false;    }    return true;}int main(){    int T;    int a,b;    scanf("%d",&T);    while(T--){        bool ans=0;        memset(flag,false,sizeof(flag));        scanf("%d %d",&a,&b);        queue <P> q;        q.push(make_pair(a,0));        flag[a]=true;        while(!q.empty()){            P now=q.front();            q.pop();            if(now.first==b){                ans=1;                printf("%d\n",now.second);                break;            }            int dig1=now.first/1000;            int dig2=(now.first/100)%10;            int dig3=(now.first/10)%10;            int dig4=now.first%10;            for(int i=1;i<=9;i++){                if(flag[i*1000+dig2*100+dig3*10+dig4]==false&&is_prime(i*1000+dig2*100+dig3*10+dig4)==true){                    flag[i*1000+dig2*100+dig3*10+dig4]=true;                    q.push(make_pair(i*1000+dig2*100+dig3*10+dig4,now.second+1));                }            }            for(int i=0;i<=9;i++){                if(flag[dig1*1000+i*100+dig3*10+dig4]==false&&is_prime(dig1*1000+i*100+dig3*10+dig4)==true){                    flag[dig1*1000+i*100+dig3*10+dig4]=true;                    q.push(make_pair(dig1*1000+i*100+dig3*10+dig4,now.second+1));                }            }            for(int i=0;i<=9;i++){                if(flag[dig1*1000+dig2*100+i*10+dig4]==false&&is_prime(dig1*1000+dig2*100+i*10+dig4)==true){                    flag[dig1*1000+dig2*100+i*10+dig4]=true;                    q.push(make_pair(dig1*1000+dig2*100+i*10+dig4,now.second+1));                }            }            for(int i=0;i<=9;i++){                if(flag[dig1*1000+dig2*100+dig3*10+i]==false&&is_prime(dig1*1000+dig2*100+dig3*10+i)==true){                    flag[dig1*1000+dig2*100+dig3*10+i]=true;                    q.push(make_pair(dig1*1000+dig2*100+dig3*10+i,now.second+1));                }            }        }        if(ans==0){            puts("Impossible");        }    }}

Pushing Boxes

原题

POJ - 1475 http://poj.org/problem?id=1475

题意

给出一张用字符表示的图,让你求出人把箱子从起始点推向目标点的路径,如果不行,输出

Impossible.(注意”.”号,一个大坑)

题解

具体思路

难点有2个,第一是路径怎么输出?我们用结构体依次维护每种状态的路径,这样写比较方

便,当然似乎可以回溯路径;

第二是限制状态很多,怎样搜索?我们可以把问题缩小,先bfs箱子的路径,在bfs人的路径,这

样问题就变成了这样:箱子每动一步(此时已保证箱子肯定能动),就看作人从当前位置走向

某一位置(推的方向相反的位置),再搜索一遍,因为题目要先保证箱子推动次数最少,所以在

优先级上,先bfs箱子的路径,在bfs人的路径.

AC代码

#include<iostream>#include<cstdio>#include<map>#include<queue>#include<algorithm>#include<cstring>using namespace std;const int MAXN=30;const int INF=1e9;char maze[MAXN][MAXN];char db[4]= {'S','N','E','W'};char dp[4]= {'s','n','e','w'};int dx[4]= {1,-1,0,0};int dy[4]= {0,0,1,-1};int r,c;int ex1,ey1;bool flagp[MAXN][MAXN];bool flagb[MAXN][MAXN];struct state {    int bx,by;    int px,py;    string ans;} ;state start,now;struct node {    int x;    int y;    string ans;};node nd,tmp;bool check(int x,int y) {    if(x<0||x>=r||y<0||y>=c) return false;    return true;}bool bfs_person(int sx,int sy,int ex,int ey) {    memset(flagp,false,sizeof(flagp));    nd.x=sx;    nd.y=sy;    nd.ans="";    flagp[nd.x][nd.y]=1;    flagp[start.bx][start.by]=1;    queue<node> qq;    qq.push(nd);    while (!qq.empty()) {        nd=qq.front();        qq.pop();        if (nd.x==ex&&nd.y==ey)            return true;        for (int i=0; i<=3; i++) {            int nx=nd.x+dx[i];            int ny=nd.y+dy[i];            if (check(nx,ny)&&maze[nx][ny]!='#'&&!flagp[nx][ny]) {                flagp[nx][ny]=1;                tmp.ans=nd.ans+dp[i];                tmp.x=nx;                tmp.y=ny;                qq.push(tmp);            }        }    }    return false;}bool bfs_box() {    queue<state> q;    q.push(start);    while(!q.empty()) {        start=q.front();        q.pop();        for(int i=0; i<=3; i++) {            int nx=start.bx+dx[i];            int ny=start.by+dy[i];            int tx=start.bx-dx[i];            int ty=start.by-dy[i];            if(check(nx,ny)&&maze[nx][ny]!='#'&&check(tx,ty)&&!flagb[nx][ny]&&maze[tx][ty]!='#') {                if(bfs_person(start.px,start.py,tx,ty)){                    flagb[nx][ny]=1;                    now.px=start.bx;                    now.py=start.by;                    now.bx=nx;                    now.by=ny;                    now.ans=start.ans+nd.ans+db[i];                    if(nx==ex1&&ny==ey1){                        return true;                    }                    q.push(now);                }            }        }    }    return false;}int main() {    int ca=0;    while(~scanf("%d %d",&r,&c)) {        if(r==0&&c==0) break;        memset(flagb,false,sizeof(flagb));        getchar();        for(int i=0; i<r; i++) {            for(int j=0; j<c; j++) {                scanf("%c",&maze[i][j]);                if(maze[i][j]=='B') {                    start.bx=i;                    start.by=j;                    flagb[i][j]=1;                }                if(maze[i][j]=='S') {                    start.px=i;                    start.py=j;                }                if(maze[i][j]=='T') {                    ex1=i;                    ey1=j;                }            }            if(i!=r-1) getchar();        }        start.ans="";        printf("Maze #%d\n",++ca);        if(bfs_box()){            cout<<now.ans<<endl;        }        else puts("Impossible.");        puts("");    }    return 0;}

Dearboy’s Puzzle

原题

POJ - 2308 http://poj.org/problem?id=2308

题意

连连看问题,具体看题面吧,大致就是给出当前局面,判断能不能消掉所有的块

题解

具体思路

我们注意到消方块的不同顺序是会影响结果的,所以先dfs消块的顺序,对于已确定的顺序

在bfs如何去消,但是这样是会TLE的,我们可以加两步剪枝,第一步是一开始判断场上的方

块数量,如果有奇数的直接输出no,第二个是特判第二种样例的情况(在dfs处剪枝)

AC代码

#pragma GCC optimize(2)#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;int times=0;int dx[4]={1,0,0,-1};int dy[4]={0,1,-1,0};int mp[11][11],num[4];int n,m;bool flag;struct node {    int x,y;    int turn;    int type,d;};bool check(int x,int y){        if(x<0||x>=n||y<0||y>=m) return false;        return true;    }void bfs(int x,int y,int v,int s[25][2],int &cnt) {    cnt=0;    queue<node>q;    node start,now;    start.x=x;    start.y=y;    start.type=-1;    start.turn=0;    start.d=-1;    bool flag[11][11];    memset(flag,false,sizeof(flag));    flag[x][y]=true;    q.push(start);    while (!q.empty()) {        start=q.front();        q.pop();        if (start.type==v) {            s[cnt][0]=start.x;            s[cnt++][1]=start.y;            continue;        }        for (int i=0; i<4; i++) {            now.x=start.x+dx[i];            now.y=start.y+dy[i];            if (check(now.x,now.y)&&!flag[now.x][now.y]) {                if (mp[now.x][now.y]!=-1&&mp[now.x][now.y]!=v) continue;                if (start.d==i||start.d==-1)                    now.turn=start.turn;                else                    now.turn=start.turn+1;                if (now.turn<=2) {                    now.type=mp[now.x][now.y];                    now.d=i;                    flag[now.x][now.y]=true;                    q.push(now);                }            }        }    }}void FO(){    freopen("in.txt","r",stdin);}bool judge(){    for(int i=0;i<n;i++){        for(int j=0;j<m;j++){            if(num[mp[i][j]]==2&&num[mp[i+1][j]]==2&&mp[i][j]==mp[i+1][j+1]&&mp[i+1][j]==mp[i][j+1]) return false;        }    }    return true;}void dfs(int cnt) {    if (flag) return ;    if (cnt==0) {        flag=true;        return;    }    if(judge()==false) return ;    for (int i=0; i<n; i++) {        for (int j=0; j<m; j++) {            if (mp[i][j]!=-1) {                int s[25][2];                int sum;                int v=mp[i][j];                bfs(i,j,v,s,sum);                num[v]-=2;                mp[i][j]=-1;                for (int k=0; k<sum; k++) {                    int x=s[k][0];                    int y=s[k][1];                    mp[x][y]=-1;                    dfs(cnt-2);                    mp[x][y]=v;                }                num[v]+=2;                mp[i][j]=v;            }        }    }}int main() {    int i,j;//  FO();    while (~scanf("%d%d",&n,&m)) {        if (n==0&&m==0) break;        getchar();        flag=false;        memset(num,0,sizeof(num));        memset(mp,-1,sizeof(mp));        int all=0;        char tmp;        for (i=0; i<n; i++) {            for (j=0; j<m; j++) {                tmp=getchar();                if (tmp=='*') mp[i][j]=-1;                else if (tmp=='A') {                    num[0]++;                    mp[i][j]=0;                    all++;                } else if (tmp=='B') {                    num[1]++;                    mp[i][j]=1;                    all++;                } else if (tmp=='C') {                    num[2]++;                    mp[i][j]=2;                    all++;                } else {                    num[3]++;                    mp[i][j]=3;                    all++;                }            }            if(i!=n-1) getchar();        }         if (num[0]%2||num[1]%2||num[2]%2||num[3]%2) {            printf("no\n");            continue;        }        dfs(all);        if (flag==true)            printf("yes\n");        else            printf("no\n");    }    return 0;}

Eight

原题

POJ - 1077 http://poj.org/problem?id=1077

题意

压轴登场,经典的八数码问题

题解

具体思路

这题写法非常多,A*,IDA*,康托展开都能做,这里讲一种利用康托展开哈希的做法,主要是优

化判重(因为自定义数据类型的map太慢,会TLE)我们把康托展开的每一种状态看作1-9的

一种排列方式,这样我们就得到了每种状态的哈希值,之后根据它判重就行了

AC代码

#include<stdio.h>#include<queue>#include<string.h>#include<iostream>#include<algorithm>using namespace std;const int MAXN=1000000;int fac[]= {1,1,2,6,24,120,720,5040,40320,362880};bool vis[MAXN];int cantor(int s[]) {    int sum=0;    for(int i=0; i<9; i++) {        int num=0;        for(int j=i+1; j<9; j++)            if(s[j]<s[i])num++;        sum+=(num*fac[9-i-1]);    }    return sum+1;}struct Node {    int s[9];    int loc;    int status;    string path;};string path;int aim=46234;int dx[4]={-1,1,0,0};int dy[4]={0,0,-1,1}; char dans[4]={'u','d','l','r'};Node ncur;bool bfs() {    Node cur,next;    queue<Node>q;    q.push(ncur);    while(!q.empty()) {        cur=q.front();        q.pop();        if(cur.status==aim) {            path=cur.path;            return true;        }        int x=cur.loc/3;        int y=cur.loc%3;        for(int i=0; i<4; i++) {            int nx=x+dx[i];            int ny=y+dy[i];            if(nx<0||nx>2||ny<0||ny>2)continue;            next=cur;            next.loc=nx*3+ny;            next.s[cur.loc]=next.s[next.loc];            next.s[next.loc]=0;            next.status=cantor(next.s);            if(!vis[next.status]) {                vis[next.status]=true;                next.path=next.path+dans[i];                if(next.status==aim) {                    path=next.path;                    return true;                }                q.push(next);            }        }    }    return false;}int main() {        memset(vis,false,sizeof(vis));    char ch;    while(cin>>ch) {        if(ch=='x') {            ncur.s[0]=0;            ncur.loc=0;        } else ncur.s[0]=ch-'0';        for(int i=1; i<9; i++) {            cin>>ch;            if(ch=='x') {                ncur.s[i]=0;                ncur.loc=i;            } else ncur.s[i]=ch-'0';        }        ncur.status=cantor(ncur.s);        if(bfs()) {            cout<<path<<endl;        }         else cout<<"unsolvable"<<endl;    }    return 0;}
原创粉丝点击