bfs练习题

HDU1973

题意:给你两个1000到9999的四位数,对于第一个数可多次任意改变一位数字,使得第一个数等于第二个数,并且第一个数字改变之后还是素数,求最少的改变次数
思路:利用bfs的特性,第一个到达的就是最短的,所以当s==e时可直接输出最少改变的次数,对于素数的处理可以预处理一下,更快,或者当场判断也行,然后就是怎么改变的问题,两个for循环对于第i位可改变为j,注意剪枝和对数组的清空,这是多组输入。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 1e5+10;
struct node{
    int num, ans;
};
bool check(int x){
    if(x<1000||x>9999) return 0;
    int j = 2; 
    while(x%j!=0) j++;
    if(j==x) return 1;
    else return 0;
}
void bfs(int s, int e){
    queue<node> q;
    int vis[10010];
    memset(vis, 0, sizeof(vis));
    vis[s] = 1;
    q.push(node{s, 0});
    while(!q.empty()){
        node cnt = q.front();
        q.pop();
        if(cnt.num==e){
            printf("%d\n", cnt.ans);
            break;
        }
        int c[4], tmp = cnt.num;
        for(int i = 0; i < 4; i++){
            c[i] = tmp%10;
            tmp /= 10;
        }
        for(int i = 0; i < 4; i++){
            for(int j = 0; j <= 9; j++){
                int k = cnt.num - pow(10, i)*c[i] + pow(10, i)*j;
                if(vis[k]==0&&check(k)){
                    //cout<<k<<endl;
                    q.push(node{k, cnt.ans+1});
                    vis[k] = 1;
                }
            }
        }
    }
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        int s, e;
        scanf("%d%d", &s, &e);
        bfs(s, e);
    }
    return 0;
}

HDU1253
题意:首先它给了一个三维的立体图形,可以变为三维的数组,问从(0,0,0)到(a-1,b-1,c-1)需要多少步,且步数不能超过minn,如果超过则输出-1
思路:相对于普通的bfs来说,这个题目把二维的变为了三维,方向由四个变为了六个,其他的就是和bfs的模板题差不多

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 50+10;
int board[maxn][maxn][maxn];
bool vis[maxn][maxn][maxn];
int dirx[6] = {1, 0, -1, 0, 0, 0};
int diry[6] = {0, 1, 0, -1, 0, 0};
int dirz[6] = {0, 0, 0, 0, 1, -1};
int a, b, c, minn;
struct node{
    int x, y, z, ans;
};
bool check(int x, int y, int z){
    if(x>=a||x<0||y>=b||y<0||z>=c||z<0) return 0;
    if(vis[x][y][z]||board[x][y][z]) return 0;
    return 1;
}
void bfs(){
    int flag = -1;
    queue<node> q;
    memset(vis, 0, sizeof(vis));
    q.push(node{0,0,0,0});
    vis[0][0][0] = 1;
    while(!q.empty()){
        node cnt = q.front();
        q.pop();
        if(cnt.ans>minn){
            break;
        }
        if((cnt.x==a-1&&cnt.y==b-1&&cnt.z==c-1)){
            flag = cnt.ans;
            break;
        }
        for(int i = 0; i < 6; i++){
            int ix = cnt.x+dirx[i];
            int iy = cnt.y+diry[i];
            int iz = cnt.z+dirz[i];
            if(check(ix, iy, iz)){
                q.push(node{ix, iy, iz, cnt.ans+1});
                vis[ix][iy][iz] = 1;
            }
        }
    }
    printf("%d\n", flag);
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d%d%d", &a, &b, &c, &minn);
        for(int i = 0; i < a; i++){
            for(int j = 0; j < b; j++){
                for(int k = 0; k < c; k++){
                    scanf("%d", &board[i][j][k]);
                }
            }
        }
        bfs();
    }
    return 0;
}

HDU1175
题意:中文题,给你一个n*m的图,k个询问,每次询问为四个数分别为起点和终点(可以这么说吧),首先要判断起点和终点在图中的数值是否一致,而且还要注意起点和终点是否重合(这个数据里面没有表现,因为无论是判断了还是没有判断都ac了,按照常理来说是不能一致的),然后问从起点到终点经过的路径只能有两个拐点,且通过的路径只能为数字0,问是否存在这样的一条路径
思路:bfs+减枝,定义一个结构体分别表示当前状态的坐标x,y,和当前的转角turn,当前的方向di,用vis表示起点到这个点最少经过的转角,然后就是判断里面的分析
1.经过改变的ix,iy要在图里面,同时board[ix][iy]=0。
2.turn要<=2,同时如果vis[ix][iy]!=0,那么需要turn<vis[ix][iy],取最优,也相当于一下的减枝。
3.如果turn=2时如果当前的点没有与终点在同一行或者是同一列就可以直接舍去。
同时为了判断的方便把board[ex][ey]赋值为0,之后赋值回去,更加简洁。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 1e3+10;
int sx, sy, ex, ey, n, m;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int board[maxn][maxn];
int vis[maxn][maxn];
struct node{
    int x, y;
    int turn, di;
};
bool check(int x, int y, int turn){
    if(x>n||x<=0||y>m||y<=0||turn>2) return 0;
    if(board[x][y]==0){
        if(vis[x][y]==0) return 1;
        else if(vis[x][y]>turn){
            vis[x][y]=turn;
            return 1;
        }else return 0;
    }
    return 0;
}
void bfs(){
    queue<node> q;
    q.push(node{sx, sy, -1, -1});
    memset(vis, 0, sizeof(vis));
    vis[sx][sy] = 1;
    board[ex][ey] = 0;
    int flag = 0;
    while(!q.empty()){
        node cnt = q.front();
        q.pop();
        if(cnt.x==ex&&cnt.y==ey&&cnt.turn<=2){
            flag = 1;break;
        }
        if(cnt.turn==2 && !(cnt.x==ex||cnt.y==ey)) continue;
        for(int i = 0; i < 4; i++){ 
            int ix = cnt.x+dir[i][0];
            int iy = cnt.y+dir[i][1];
            int turn = cnt.turn;
            if(i!=cnt.di) turn++;           
            if(check(ix, iy, turn)){
                vis[ix][iy] = turn;
                q.push(node{ix, iy, turn, i});
            }
        }
    }
    if(flag) printf("YES\n");
    else printf("NO\n");
}
int main(){
    while(scanf("%d%d", &n, &m), n&&m){
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%d", &board[i][j]);
            }
        }
        int k;
        scanf("%d", &k);
        while(k--){
            scanf("%d%d%d%d", &sx, &sy, &ex, &ey);
            if(board[ex][ey]==board[sx][sy]&&board[ex][ey]&&!(sx==ex&&sy==ey)){
                int tmp = board[ex][ey];
                bfs();
                board[ex][ey] = tmp;
            }else printf("NO\n");
        }
    }
    return 0;
}

POJ3414

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值