第十一届湖南省省赛 - 简单的图论问题?(BFS)

简单的图论问题?


题目描述

给一个 n  m 列的迷宫,每个格子要么是障碍物要么是空地。每个空地里都有一个权值。你的

任务是从找一条(r1,c1)(r2,c2)的路径,使得经过的空地的权值之和最小。每一步可以往上下

左右四个方向之一移动一格,但不能斜着移动,也不能移动到迷宫外面或者进入障碍物格子。

 

如下图,灰色格子代表障碍物。路径 A->B->D->F->E 的权值为 10+3+6+14+8=41,它是从 A 

E 的最优路径。注意,如果同一个格子被经过两次,则权值也要加两次。

                   


A

B

G


C

D

H


E

F












7

10

3

9


45

6

2


8

14


21

1




为了让题目更有趣(顺便增加一下难度),你还需要回答另外一个问题:如果你每次必须转弯

(左转、右转或者后退,只要不是沿着上次的方向继续走即可),最小权值是多少?比如,在

上图中,如果你刚刚从 A 走到 B,那么下一步你可以走到 D 或者 A,但不能走到 G。在上图

中,A  E 的最优路径是 A->B->D->H->D->F->E,权和为 10+3+6+2+6+14+8=49。注意,D 

过了两次。



输入描述

输入包含不超过10组数据。每组数据第一行包含6个整数n, m, r1, c1, r2, c2 (2<=n,m<=500, 1<=r1,r2<=n, 1<=c1,c2<=m). 接下来的n行每行包含m个格子的描述。每个格子要么是一个1~100的整数,要么是星号"*"(表示障碍物)。起点和终点保证不是障碍物。


输出描述

对于每组数据,输出两个整数。第一个整数是“正常问题”的答案,第二个整数是“有趣问题”的答案。如果每个问题的答案是“无解”,对应的答案应输出-1。


输入样例
4 4 1 2 3 2
7 10 3 9
* 45 6 2
* 8 14 *
21 1 * *
2 4 1 1 1 4
1 2 3 4
9 * * 9
2 4 1 1 1 4
1 * 3 4
9 9 * 9

输出样例

Case 1: 41 49 Case 2: 10 -1 Case 3: -1 -1

这个题目纯粹水题,第一问大家都会,第二问只要简单的记录一下路径方向就可以了

C++:

#include <map>
#include <set>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <queue>
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <algorithm>
using namespace std;


#define pb push_back
#define fillchar(a, x) memset(a, x, sizeof(a))
#define copy(a, b) memcpy(a, b, sizeof(a))


typedef long long LL;
typedef pair<int, int > PII;
typedef unsigned long long uLL;
template<typename T>
void print(T* p, T* q, string Gap = " ") {
    int d = p < q ? 1 : -1;
    while(p != q) {
        cout << *p;
        p += d;
        if(p != q) cout << Gap;
    }
    cout << endl;
}
template<typename T>
void print(const T &a, string bes = "") {
    int len = bes.length();
    if(len >= 2)cout << bes[0] << a << bes[1] << endl;
    else cout << a << endl;
}

const int INF = 0x3f3f3f3f;
const int MAXM = 1e5;
const int MAXN = 5e2 + 5;
int n, m, r1, c1, step1, step2, r2, c2, mp[MAXN][MAXN];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};
bool vis[MAXN][MAXN],viss[MAXN][MAXN][4];
char op[5];

struct point{
    int x, y, step, dist;
    point(int x,int y,int step):x(x),y(y),step(step){}
    point(int x,int y,int dist,int step):x(x),y(y),dist(dist),step(step){}
    bool operator >(const point & a) const{
        return step > a.step;
    }
};

void BFS1(){
    memset(vis, false, sizeof(vis));
    priority_queue<point,vector<point>, greater<point> > que;
    que.push(point(r1, c1, 0));
    vis[r1][c1] = true;
    while(!que.empty()){
        point e = que.top();
        que.pop();
        if(e.x == r2 && e.y == c2) {
            step1 = e.step;
            return;
        }
        for(int i = 0;i < 4;i ++){
            int nx = e.x + dx[i];
            int ny = e.y + dy[i];
            if(nx <= 0 || ny <= 0|| nx > n || ny > m || vis[nx][ny] || mp[nx][ny] == -1) continue;
            vis[nx][ny] = true;
            que.push(point(nx, ny, e.step + mp[nx][ny]));
        }
    }
}

void BFS2(){
    memset(viss, false, sizeof(viss));
    priority_queue<point,vector<point>, greater<point> > que;
    que.push(point(r1, c1, 0, 0));
    que.push(point(r1, c1, 1, 0));
    que.push(point(r1, c1, 2, 0));
    que.push(point(r1, c1, 3, 0));
    viss[r1][c1][0] = viss[r1][c1][1] = viss[r1][c1][2] = viss[r1][c1][3] = true;
    while(!que.empty()){
        point e = que.top();
        que.pop();
        if(e.x == r2 && e.y == c2) {
            step2 = e.step;
            return;
        }
        for(int i = 0;i < 4;i ++){
            if(i == e.dist) continue;
            int nx = e.x + dx[i];
            int ny = e.y + dy[i];
            if(nx <= 0 || ny <= 0|| nx > n || ny > m || viss[nx][ny][i] || mp[nx][ny] == -1) continue;
            viss[nx][ny][i] = true;
            que.push(point(nx, ny, i, e.step + mp[nx][ny]));
        }
    }
}

int main(){
    int cas = 1;
    while(cin >> n >> m >> r1 >> c1 >> r2 >> c2){
        step2 = step1 = -1;
        for(int i = 1;i <= n;i ++){
            for(int j = 1;j <= m;j ++){
                cin >> op;
                if(op[0] == '*'){
                    mp[i][j] = -1;
                }
                else{
                    mp[i][j] = atoi(op);
                }
            }
        }
        BFS1();
        BFS2();
        if(step1 != -1) step1 += mp[r1][c1];
        if(step2 != -1) step2 += mp[r1][c1];
        printf("Case %d: %d %d\n",cas ++, step1, step2);
    }
    return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值