回顾-搜索

1. POJ 3414 Pots

POJ 3414 Pots

题意 有两个杯子体积是 A B 用三个操作,达到其中一种杯子变成C体积

  1. FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap; (将i杯子装满水)
  2. DROP(i) empty the pot i to the drain;(将i杯子水全倒掉)
  3. POUR(i,j) pour from pot i to pot j;after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).(将i的水倒入j中,当i没水和j满时停止)
    分析:bfs搜索最短步数 构造一个node 存储 当前状态 除了步数和ab的水量 还记录路径 在得到c体积之后输出路径
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<cstdio>
using namespace std;

const int N = 220;
struct Node{
    int a,b,step;//a b 瓶中水体积 步数
    string s;//记录路径
}node;

int vis[N][N];
int A,B,C;
string zou[10]={"","FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};//六种选择
bool flag=0;//标记找不到的情况 wa了两发

//广搜
void bfs()
{
    queue<Node>q;
    q.push(Node{0,0,0,"0"});
    vis[0][0]=1;

    while(q.size())
    {
        node=q.front();
        q.pop();
        //cout<<node.a<<' '<<node.b<<' '<<node.step<<endl;
        if(node.a==C||node.b==C)
        {
            flag=1;
            printf("%d\n",node.step);
            for(int i=1;i<=node.step;i++)
                cout<<zou[node.s[i]-'0']<<endl;
            return;
        }
        //各操作 有效 然后 没有遍历过
        if(node.a<A)
        {
            if(!vis[A][node.b])
            {
                vis[A][node.b]=1;
                q.push(Node{A,node.b,node.step+1,node.s+"1"});
            }
        }

        if(node.b<B)
        {
            if(!vis[node.a][B])
            {
                vis[node.a][B]=1;
                q.push(Node{node.a,B,node.step+1,node.s+"2"});
            }
        }

        if(node.a!=0)
        {
            if(!vis[0][node.b])
            {
                vis[0][node.b]=1;
                q.push(Node{0,node.b,node.step+1,node.s+"3"});
            }
        }

        if(node.b!=0)
        {
            if(!vis[node.a][0])
            {
                vis[node.a][0]=1;
                q.push(Node{node.a,0,node.step+1,node.s+"4"});
            }
        }

        if(node.a>0&&node.b!=B)
        {
            int c=node.a-(B-node.b),x,y;
            if(c<=0)x=0,y=node.b+node.a;
            else x=c,y=B;

            if(!vis[x][y])
            {
                vis[x][y]=1;
                q.push(Node{x,y,node.step+1,node.s+"5"});
            }
        }

        if(node.b>0&&node.a!=A)
        {
            int c=node.b-(A-node.a),x,y;
            if(c<=0)x=node.a+node.b,y=0;
            else x=A,y=c;

            if(!vis[x][y])
            {
                vis[x][y]=1;
                q.push(Node{x,y,node.step+1,node.s+"6"});
            }
        }
    }

}

int main()
{
    scanf("%d%d%d",&A,&B,&C);

    bfs();

    if(!flag)printf("impossible\n");

    return 0;
}

类似题目:
HDU - 1495 非常可乐
—————————————————————————————

2. HDU2612 Find a way

HDU2612 Find a way
题意:有两个人在各自位置找KFC 找到一个KFC使他们俩使用的时间最短
分析:使用双bfs 将两个人的KFC都搜索一遍 最后找到最短时间的KFC
开始我是记录每个kfc的位置然后每个kfc搜一次bfs TL了 耗时了
后来看了题解 把每个人的全部kfc都搜一遍,再在图中寻找到耗时最短的kfc只使用了两次bfs所以不会超时

#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;

const int N =300;

int n,m;
int d[N][N];
int mk[N][N];
string tu[N];

typedef struct Pair{
   int x,y,t;//位置 和 步数
   node(int x_=0,int y_=0,int t_=0)
   {
       x = x_,y = y_, t = t_;
   }
}node;

int yx,yy,mx,my;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};

void  bfs(int sx,int sy)//搜全图
{
    queue<Pair>q;
    q.push(Pair{sx,sy,0});
    mk[sx][sy]=0;
    while(q.size())
    {
        Pair p=q.front();
        q.pop();
        //if(p.first==e.first&&p.second==e.second)continue;
        for(int i=0;i<4;i++)
        {
            int x=p.x+dx[i],y=p.y+dy[i];
            if(x<0||x>=n||y<0||y>=m)continue;
            if(tu[x][y]=='#')continue;
            if(mk[x][y])continue;
            if(tu[x][y]=='@')d[x][y]+=p.t+1;

            mk[x][y]=1;
            q.push(Pair{x,y,p.t+1});
        }

    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(d,0,sizeof(d));
        for(int i=0;i<n;i++)
        {
            cin>>tu[i];
            for(int j=0;j<m;j++)
            {
                if(tu[i][j]=='Y')yx=i,yy=j;
                if(tu[i][j]=='M')mx=i,my=j;
            }
        }
        //使用两次bfs 两个点到各个点的时间
        memset(mk,0,sizeof(mk));
        bfs(yx,yy);//搜索y的整个图
        memset(mk,0,sizeof(mk));
        bfs(mx,my);//搜索m的整个图
        //cout<<ken.size()<<endl;
        int s = INT_MAX;//设置为一个最大数
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            if(tu[i][j]=='@'&&mk[i][j])s=min(s,d[i][j]);
        }
        printf("%d\n",s*11);

    }
    return 0;
}

3. HDU 2181 哈密顿绕行世界问题

HDU 2181 哈密顿绕行世界问题
题意:有二十个城市,第i行代表城市i邻居的三个城市,给你一个起点m,从m开始找到一条可以环游所有城市并且最后回到m的路线
分析:dfs 第一个必然是m 标记为走过,然后一层层走,走到20,判断最后一个点能不能回到m ,可以回到计数并且输出 这条路

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

int a[21][4];//记录每个城市邻居的三个城市
int m;//起点
int d[21];//记录走过顺序
bool vis[21];//记录城市是否走过
int c=0;//计数路

void dfs(int r,int index)//层数 当前行
{
    if(r>=20)
    {
        if(a[d[19]][1]==m||a[d[19]][2]==m||a[d[19]][3]==m)//是否可以回到起点
        {
            c++;
            printf("%d:  ",c);//两个  空格
            for(int i=0;i<20;i++)
                printf("%d ",d[i]);
            printf("%d\n",m);//最后输出起点
        }
    }
    else
    {
        for(int i=1;i<=3;i++)
        {
            if(!vis[a[index][i]])
            {

                vis[a[index][i]]=true;
                d[r]=a[index][i];
                //cout<<index<<' '<<i<<' '<<a[index][i]<<' '<<d[r]<<endl;
                dfs(r+1,a[index][i]);
                vis[a[index][i]]=false;
            }
        }
    }

}

int main()
{
    for(int i=1;i<=20;i++)
    {
        for(int j=1;j<=3;j++)
            scanf("%d",&a[i][j]);
    }
    while(1)
    {
        scanf("%d",&m);
        if(m==0)break;
        memset(vis,0,sizeof(vis));
        d[0]=m;
        vis[m]=true;
        c=0;
        dfs(1,m);
        if(c==0)printf("\n");
    }
    return 0;
}


4. HDU2102 A计划

HDU2102 A计划

题意:在两层地图 中 从S到P 救出公主 走一步1个时间,只能前后左右走,层数跳跃只能通过‘#’无条件跳转另一层,遇到‘*’死掉,问能不能在T时间救出公主
分析:一个正常的bfs 寻找最少步数
一坑 遇到空间跳转‘#’除了遇到墙‘*’死,再遇到‘#’也死 wa了两发

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<string>
using namespace std;

const int MAX = 30;
struct Node{
    int x,y,z,step;//当前位置 步数
}p;

int t,N,M,T;
int ex,ey,ez;//开始
int sx,sy,sz;//终点
string tu[MAX][MAX];
bool vis[MAX][MAX][MAX];//标记点状态
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};

int bfs()
{
    queue<Node>q;
    q.push(Node{ex,ey,ez,0});
    memset(vis,0,sizeof(vis));

    vis[0][0][0]=true;

    while(q.size())
    {
        p=q.front();
        q.pop();
        //cout<<p.x<<' '<<p.y<<' '<<p.z<<' '<<p.step<<endl;
        if(p.x==sx&&p.y==sy&&p.z==sz)return p.step;
        for(int i=0;i<4;i++)
        {
            int x=p.x+dx[i],y=p.y+dy[i],z=p.z;
            if(x<0||x>=N||y<0||y>=M)continue;//超出图的范围
            if(tu[z][x][y]=='*')continue;//墙
            if(tu[z][x][y]=='#')//空间跳转
            {
                int o;
                if(z==1)o=0;
                else o=1;
                if(tu[o][x][y]=='*'||tu[o][x][y]=='#')continue;//跳转之后到另一层 除了不能是墙 也不能是空间跳转
                else z=o;
            }
            if(!vis[z][x][y])
            {

                vis[z][x][y]=true;
                q.push(Node{x,y,z,p.step+1});

            }
        }

    }
    return INT_MAX;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&N,&M,&T);

        for(int k=0;k<2;k++)
        {
            for(int i=0;i<N;i++)
            {
                cin>>tu[k][i];
                for(int j=0;j<M;j++)
                {
                    if(tu[k][i][j]=='S')ex=i,ey=j,ez=k;
                    if(tu[k][i][j]=='P')sx=i,sy=j,sz=k;
                    //cout<<sx<<sy<<sz<<endl;
                }
            }
        }

        int s=bfs();
        //cout<<s<<endl;
        if(s<=T)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
/*
4
5 5 13
S*#*.
.#...
.....
****.
...#.

..*.P
#....
***..
...*.
*.#..
5 5 14
S*#*.
.#...
.....
****.
...#.

..*.P
#.*..
***..
...*.
*.#..
5 5 14
S*#*.
.#...
.....
****.
...#.

..*.P
#.*..
***..
...*.
*.#*.
5 5 14
S*#*.
.#...
.....
****.
...#.

..**P
#.*.*
***..
...*.
*.#*.
*/
/*
ans:
YES
YES
NO
NO
*/

5. Acwing 3825. 逃离大森林

Acwing 3825. 逃离大森林
题意:在一块地图上,操作有两种:原地不动或上下左右移动一格。你要从起点走到终点,这个地图还有其它玩家,其它玩家也阔以移动,如果在一个格子碰到其它玩家,则要跟这个玩家打一架才阔以继续走,问最小的打架数是多少

分析:先来转化一下,如果其它玩家想和你在去终点的路上相遇,ta肯定也阔以到达终点才可以在路上碰到你,也就是说在路上碰到的人一定阔以到达终点,而且如果想打架,ta一定要比你早到或同时这个点,也就是说,其它玩家到达终点的距离 < 我到达终点的距离
分析完,最后跑一遍bfs,得到所有玩家到终点的距离,将所有阔以到达终点并且小于我的距离的人数加起来就是我要打架的人数

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>

using namespace std;

int r,l;
char a[1100][1100];
int sx,sy,ex,ey,mi=0;
typedef pair<int,int>Pair;
int d[1100][1100];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};

int bfs()
{
    memset(d,0x3f,sizeof(d));
    queue<Pair>q;
    q.push(Pair{ex,ey});
    d[ex][ey]=0;
    while(q.size())
    {
        Pair t=q.front();
        q.pop();
        
        for(int i=0;i<4;i++)
        {
            int x=t.first+dx[i],y=t.second+dy[i];
            if(a[x][y]=='T')continue;
            if(x<0||x>=r||y<0||y>=l)continue;
            if(d[x][y]>d[t.first][t.second]+1)
            {
                d[x][y]=d[t.first][t.second]+1;
                q.push(Pair{x,y});
            }
        }
    }
    return d[sx][sy];
}

int main()
{
    scanf("%d%d",&r,&l);
    for(int i=0;i<r;i++)
    {
        scanf("%s",a[i]);
        for(int j=0;j<l;j++)
        {
            if(a[i][j]=='S')sx=i,sy=j;
            if(a[i][j]=='E')ex=i,ey=j;
        }
    }
    int t=bfs();
    //cout<<t<<endl;
    for(int i=0;i<r;i++)
        for(int j=0;j<l;j++)
            if(a[i][j]>'0'&&a[i][j]<='9'&&d[i][j]<=t)
                mi+=a[i][j]-'0';
    printf("%d\n",mi);
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值