poj 几道简单的搜索题 (一)

题目:poj 2488 A Knight's Journey
题意:

给一个m*n的棋盘,马走日,给出一条字典序最小的马的路线来走完整个棋盘?

分析:

如果能走完棋盘,那么从(1,1)点dfs即可,因为他能走完整个棋盘嘛,总有一步会经过(1,1),所以从(1,1)出发就能到其他所有点。

为了保证字典序,在枚举方向时顺序要保证x轴优先,然后y轴。

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=33;
typedef pair<int,int>pii;
vector<pii>ans;
int dx[][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};
int n,m;
bool vis[N][N];
bool dfs(int x,int y,int step)
{
    if(step==n*m)return 1;
    for(int i=0;i<8;i++){
        int xx=dx[i][0]+x;
        int yy=dx[i][1]+y;
        if(xx<1||yy<1||xx>n||yy>m||vis[xx][yy])continue;
        vis[xx][yy]=1;
        ans.push_back(make_pair(xx,yy));
        if(dfs(xx,yy,step+1)) return 1;
        vis[xx][yy]=0;
        ans.pop_back();
    }
    return 0;
}
int main()
{
    int T;scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        ans.clear();
        scanf("%d%d",&m,&n);
        ans.push_back(make_pair(1,1));
        memset(vis,0,sizeof(vis));
        vis[1][1]=1;
        printf("Scenario #%d:\n",cas);
        if(dfs(1,1,1)){
            for(int i=0;i<ans.size();i++)
                printf("%c%d",(char)('A'+ans[i].first-1),ans[i].second);
        }
        else printf("impossible");
        printf("\n\n");
    }
    return 0;
}

题目:poj 3009

题意:

滚小球,小球刚开始在起点S,每次可以往四个方向扔出,扔出后小球一直滚动,直到碰到砖块(砖块碰到后消失)或者到达终点E。问小球到E的最短路?

分析:

虽然是到类似于最短路的题目,但是似乎bfs是不行的,因为每次球发生碰撞后会改变地图,有可能出现更优解!所以要dfs找出所有的可能解(所以数据范围才小),但是要剪枝,不然会超时。

#include<cstdio>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=22;
int g[N][N];
int w,h,sx,sy;
int dx[][2]={{-1,0},{1,0},{0,-1},{0,1}};
int ans=INF;
void dfs(int x,int y,int step)
{
    if(step>=10||step>=ans)return; //剪枝
    for(int i=0;i<4;i++){
        int xx=dx[i][0]+x;
        int yy=dx[i][1]+y;
        if(g[xx][yy]==1)continue;
        while(xx>=0&&xx<w&&yy>=0&&yy<h&&g[xx][yy]!=1&&g[xx][yy]!=3)xx=dx[i][0]+xx,yy=dx[i][1]+yy;
        if(xx<0||xx==w||yy<0||yy==h)continue;
        if(g[xx][yy]==3){ans=step+1;return;} //每次更新,一定更优,因为上面已经剪过枝
        g[xx][yy]=0;
        dfs(xx-dx[i][0],yy-dx[i][1],step+1);
        g[xx][yy]=1;
    }
}
int main()
{
    while(~scanf("%d%d",&w,&h)&&(w+h)){
        ans=INF;
        for(int j=0;j<h;j++)
        for(int i=0;i<w;i++){
            scanf("%d",&g[i][j]);
            if(g[i][j]==2)sx=i,sy=j;
        }
        dfs(sx,sy,0);
        if(ans==INF)printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

题目:poj 1321

题意:

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n

分析:

要找所有方案,显然是要dfs找出所有可能解。因为放了的棋子不能在同一行或者同一列,很容易想到开两个数组标记一下有棋子的行和列,但是这似乎还不能解决这个问题,因为可能出现重复(比如这种方案是AB两点,另一种方案是BA两点),为了防止重复,可以逐行枚举,这样就不会出现重复的情况了。

#include<cstdio>
#include<cstring>
using namespace std;
const int N=10;
int n,k;
bool visy[N],g[N][N];
char s[N];
int ans;
void dfs(int row,int step)
{
    if(step==k){
        ans++;return;
    }
    for(int i=row;i<n;i++)
        for(int j=0;j<n;j++){
            if(g[i][j]&&!visy[j]){
                visy[j]=1;
                dfs(i+1,step+1);
                visy[j]=0;
            }
        }
}
int main()
{
    while(~scanf("%d%d",&n,&k)&&(~n)){
        memset(visy,0,sizeof(visy));
        ans=0;
        int sx,sy;
        for(int i=0;i<n;i++){
            scanf("%s",s);
            for(int j=0;j<n;j++)
                g[i][j]=s[j]=='#'?1:0;
        }
        dfs(0,0);
        printf("%d\n",ans);
    }
    return 0;
}


题目:poj 2251

题意:

给出一个三维的图,求S到E的最短路

分析:

裸的bfs

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define mp make_pair
const int N=33;
typedef pair<int,int>pii;
typedef pair<pii,pii>state; //步数,层,行,列,可能写个struct清晰点QAQ
char g[N][N][N];
bool vis[N][N][N];
int C,L,R,sl,sc,sr; //层数,行数,列数,开始的层行列
int d[][3]={{0,0,-1},{0,0,1},{0,-1,0},{0,1,0},{-1,0,0},{1,0,0}};
int bfs()
{
    queue<state>q;
    q.push(mp(mp(0,sl),mp(sr,sc)));
    memset(vis,0,sizeof(vis));
    vis[sl][sr][sc]=1;
    while(!q.empty()){
        state t=q.front();q.pop();
        int step=t.first.first,l=t.first.second,r=t.second.first,c=t.second.second;
        for(int i=0;i<6;i++){
            int tl=l+d[i][0],tr=r+d[i][1],tc=c+d[i][2];
            if(tl<0||tl==L||tr<0||tr==R||tc<0||tc==C||vis[tl][tr][tc]||g[tl][tr][tc]=='#')continue;
            if(g[tl][tr][tc]=='E')return step+1;
            vis[tl][tr][tc]=1;
            q.push(mp(mp(step+1,tl),mp(tr,tc)));
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d%d%d",&L,&R,&C)&&(L+R+C)){
        for(int l=0;l<L;l++)
            for(int r=0;r<R;r++){
                scanf("%s",g[l][r]);
                for(int c=0;c<C;c++)if(g[l][r][c]=='S')sl=l,sr=r,sc=c;
            }
        int t=bfs();
        if(t==-1)printf("Trapped!\n");
        else printf("Escaped in %d minute(s).\n",t);
    }
    return 0;
}










  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值