BFS例题

题目描述 原题链接

农夫知道一头牛的位置,想要抓住它。

农夫和牛都位于数轴上,农夫起始位于点 N,牛位于点 K。

农夫有两种移动方式:

从 X 移动到 X−1 或 X+1,每次移动花费一分钟
从 X 移动到 2∗X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。

农夫最少要花多少时间才能抓住牛?

输入格式
共一行,包含两个整数N和K。

输出格式
输出一个整数,表示抓到牛所花费的最少时间。

数据范围
\(0≤N,K≤10^5\)

样例

输入: 5 17
输出:4


算法1

(BFS) \(O(K)\)

题目讲述一共有3种移动情况且权重一致

  1. 从 X 移动到 X−1
  2. 从 X 移动到 X+1
  3. 从 X 移动到 2∗X

相当于X 与X - 1,X + 1,2 * X ,各连一条边,从n开始进行bfs到k,dist[k]表示k点到n点的最短距离

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

const int N = 100010;
using namespace std;
bool st[N];
int dist[N],q[N];
int s,k;

int bfs()
{
    int hh = 0, tt = 0;
    memset(dist,0x3f,sizeof dist);
    dist[s] = 0;
    st[s] = true; q[0] = s;
    
    while(hh <= tt)
    {
        int t = q[hh ++];
        if(t == k) return dist[t];
        if(2 * t < N && !st[2 * t]){
            dist[2 * t] = dist[t] + 1;
            q[++ tt] = t * 2;
            st[2 * t] = true;
        }
        if(t + 1 < N && !st[t + 1]) {
            dist[t + 1] = dist[t] + 1;
            q[++ tt] = t + 1;
            st[t + 1] = true;
        }
        if(t - 1 >= 0 && ! st[t - 1] ){
            dist[t - 1] = dist[t] + 1;
            q[++ tt] = t - 1;
            st[t - 1] = true;
        }
    }
    return dist[k];
}

int main()
{
    cin >> s >> k;
    cout <<  bfs() << endl;

}

题目描述 原题链接

题面翻译:
给你两个四位质数a,b;每次可以花1让a一个数位上的数字变换(0-9),但要保证每次变换后的数字还是一个素数,求问最少需要多少次变换让a变成b;

样例

输入:
3
1033 8179
1373 8017
1033 1033
输出:
6
7
0


算法1

(BFS)

四个数位,各有十个数字的变换可能,所以这题广搜的方向就是四十个。不断广搜直至找到要求的四位质数即可。
这道题思路并不难,但有几个麻烦;

  1. 质数的判断,每次搜出一个数后需要判断其是否为素数。我使用的方法是埃氏筛打表预处理一万以内的所有素数。
  2. 如何实现“变换”,为了方便,我采用的是字符串,也就是string类型来进行操作。使用字符串的好处,就是每次变换直接改变那个位置上的字符即可。用整型来操作会麻烦很多。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

const int N = 10010;
using namespace std;

bool st[N],vis[N];
int primes[N],cnt;
int dist[N],q[N];
int s,e;
// 筛素数,对应以后每个 st[x] 如果为 true表示素数,false表示合数
void init()
{
    for(int i = 2; i < N; i ++)
    {
        if(! st[i]) primes[++ cnt] = i;
        for(int j = 2; j <= N /  i; j ++) st[i * j] = true;
    }
}
// 字符转换操作
int change(char str[])
{
    int ret = 0;
 
    for(int i = 0; i < 4; i ++) 
        ret = ret * 10 + (str[i] - '0');
    return ret;
}


int bfs() 
{
    int hh = 0, tt = 0;
    q[0] = s;
    memset(dist,0x3f,sizeof dist);
    memset(vis,false,sizeof vis);
    vis[s] = true;
    dist[s] = 0;
    while(hh <= tt)
    {
        int t = q[hh ++];
        
        if(t == e) return dist[t];
        // 字符操作
        for(int i = 0; i < 4; i ++)
        {
            char str[4];
            for(int k = 3,p = t; k >= 0; k --)
            {
                str[k] = (p % 10 + '0');
                p /= 10;
            }
            // 枚举10种情况
            for(int j = 0; j <= 9; j ++)
            {
                if(i == 0 && j == 0) continue;
                str[i] = j + '0';
                int x = change(str);
                if(!st[x] && !vis[x])
                {
                    vis[x] = true;
                    dist[x] = dist[t] + 1;
                    q[++ tt] = x;
                }
            }
        }
    }
    return dist[e];
}

int main()
{
    init();
    int cases;
    scanf("%d",&cases);
    while(cases --)
    {
        scanf("%d%d",&s,&e);
        cout << bfs() << endl;
    }
}

题目描述 原题链接

题面翻译:

有两个容量分别为A,B的罐子,你有三种操作可以执行,1.灌满任意一个罐子 2.倒光任意一个罐子的水 3.将一个罐子的水倒到另一个罐子里。求最快需要倒几次让其中一罐的水量为C

样例

输入:
3 5 4
输出:
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)


算法1

(BFS)

每一步都有六个方向,即:

"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"

求最快的方法所以用广搜,需要记录搜索路径,所以我采用了数组进行广搜。

思路并不难,具体实现较为麻烦:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#define x first
#define y second
using namespace std;

string result[7];

bool st[110][110];
int dist[110][110];
typedef pair<int,int> PII;

PII q[10100];
const int INF = 0x3f3f3f3f;

void init()
{
    result[1] = "FILL(1)";
    result[2] = "FILL(2)";
    result[3] = "POUR(1,2)";
    result[4] = "POUR(2,1)";
    result[5] = "DROP(1)";
    result[6] = "DROP(2)";
}

int a,b,c;

struct Pre{
    int x,y,t;
} pre[110][110];
int prea,preb;
int bfs()
{
    memset(dist,0x3f,sizeof dist);
    memset(st,false,sizeof st);
    int hh = 0, tt = 0;
    q[0] = {0,0};
    dist[0][0] = 0;
    st[0][0] = true;
    
    
    while(hh <= tt)
    {
        PII t = q[hh ++];
        if(t.x == c || t.y == c)
        {
            prea = t.x,preb = t.y;
            return dist[t.x][t.y];
        }
        if(! st[a][t.y]) {
            dist[a][t.y] = dist[t.x][t.y] + 1;
            st[a][t.y] = true;
            q[++ tt] = {a, t.y};
            pre[a][t.y] = {t.x,t.y,1};
        }
        if(! st[t.x][b]) {
            dist[t.x][b] =  dist[t.x][t.y] + 1;
            st[t.x][b] = true;
            q[++ tt] = {t.x, b};
            pre[t.x][b] = {t.x, t.y, 2};
        }
        if(! st[t.x][0]) {
            dist[t.x][0] = dist[t.x][t.y] + 1;
            st[t.x][0] = true;
            q[++ tt] = {t.x, 0};
            pre[t.x][0] = {t.x,t.y,6};
        }
        if(! st[0][t.y]){
            dist[0][t.y] = dist[t.x][t.y] + 1;
            st[0][t.y] = true;
            q[++ tt] =  {0, t.y};
            pre[0][t.y] = {t.x,t.y,5};
        }
        
        int pa = t.x, pb = t.y;
        int cntb = b - pb, cnta = a - pa;   // cnta:a还能装多少, cntb:b还能装多少
        // a 给 b
        if(pa >= cntb) {pa -= cntb; pb = b;}
        else {pb += pa; pa = 0;}
        
        if(! st[pa][pb]) {
            dist[pa][pb] = dist[t.x][t.y] + 1;
            st[pa][pb] = true;
            q[++ tt] = {pa, pb};
            pre[pa][pb] =  {t.x,t.y,3};
        }
        pa = t.x,pb = t.y;
        cntb = b - pb, cnta = a - pa;
        if(pb >= cnta) {pb -= cnta; pa = a;}
        else {pa += pb; pb = 0;}
        
        
        if(! st[pa][pb]) {
            dist[pa][pb] = dist[t.x][t.y] + 1;
            st[pa][pb] = true;
            q[++ tt] = {pa,pb};
            pre[pa][pb] =  {t.x,t.y,4};
        }
    }
    
    return INF;
    
}


int main()
{
    init();
    
    scanf("%d%d%d",&a,&b,&c);
    int t = bfs();
    if(t == INF)
    {
        printf("impossible\n");
    } 
    else 
    {
        printf("%d\n",t);
    }
   stack<string> stk;
   while(prea != 0 || preb != 0) 
   {
        
        stk.push(result[pre[prea][preb].t]);
        int tmp = prea;
        prea = pre[prea][preb].x;
        preb = pre[tmp][preb].y;
        
   }
   
  while(stk.size())
  {
      cout << stk.top() <<endl;
      stk.pop();
  }
  
   return 0;
    
}
posted @ 2020-10-30 22:24  cyoking  阅读(359)  评论(0)    收藏  举报