2015年湖南省第十一届大学生程序设计大赛 E题 “简单的图论问题?” CSG - 1116(最短路,dijkstra,图论)

这篇博客详细介绍了2015年湖南省第十一届大学生程序设计大赛E题的解题过程,主要涉及图论中的最短路径问题。作者使用Dijkstra算法分别解决两种路径约束条件下的最短路径问题,一种是允许直行,另一种必须转弯。在第二种情况下,需要记录不同方向到达某点的最短路径。博客提供了解题思路和C++代码实现。

题目链接


一.题目内容

给一个n*m的矩阵,每一格要么是 * 代表障碍 ,要么是可走的1-100的整数。
① 只能上下左右走,输出从{r1,c1}到{r2,c2}最短路径,路径长度就是所走格子的和。
② 若每一步不能与前一步的方向相同,也就是只能转弯或者后退,输出从这时从{r1,c1}到{r2,c2}最短路径。
若无路径则输出 -1

样例解释

在这里插入图片描述
样例一:① 正常路线 10->3->6->14->8,值为41 。② 转弯路线 10->3->6->2->6->14->8,值为49。


二.解题思路

第一问直接dijkstra即可。
第二问也是dijkstra,但需要稍微变形。由于连续两步方向不能相同,则可以记录以下从不同方向走到某格的最短路,方向相同就不能走,若方向不同则更新对应方向的最短路,最后的结果从所有到达终点的最短路中比较得出。


三.解题代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define rrep(i, l, r) for (int i = l; i >= r; --i)
#define int long long
int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; //四个方向的数组
const int N = 1e3 + 10, M = 1e9 + 7;
//-----------//
int n, m, r1, c1, r2, c2;
int a[N][N], dis[N][N],dis2[N][N][4];//四个方向的dis
bool vis[N][N];
bool check(int x, int y) {
    return x >= 1 && x <= n && y >= 1 && y <= m && a[x][y];
}
struct node {
    int x, y, w, di;
    friend bool operator<(const node &t1, const node &t2) {
        return t1.w > t2.w;
    }
};
int dj1() { //正常dijkstra
    rep(i, 1, n) rep(j, 1, m) dis[i][j] = LLONG_MAX, vis[i][j] = 0;
    priority_queue<node> q;
    q.push(node{r1, c1, a[r1][c1], -1});
    dis[r1][c1]=0;
    while (q.size()) {
        node cur = q.top();
        q.pop();
        if (vis[cur.x][cur.y]) continue;
        if (cur.x == r2 && cur.y == c2) return dis[r2][c2];
        vis[cur.x][cur.y] = 1;
        rep(i, 0, 3) {
            int x = cur.x + dir[i][0];
            int y = cur.y + dir[i][1];
            if (check(x, y) && !vis[x][y]) {
                int d = cur.w + a[x][y];
                if (dis[x][y] > d) {
                    dis[x][y] = d;
                    q.push(node{x, y, d, i});
                }
            }
        }
    }
    return -1;
}
int dj2() { //修改版dijkstra
    rep(i, 1, n) rep(j, 1, m) rep(k,0,3) dis2[i][j][k] = LLONG_MAX;
    priority_queue<node> q;
    q.push(node{r1, c1, a[r1][c1], -1});
    rep(i,0,3) dis2[r1][c1][i]=0;
    int ans=LLONG_MAX;
    while (q.size()) {
        node cur = q.top();
        q.pop();
        if (cur.x == r2 && cur.y == c2) ans=min(ans,cur.w); 
        //若到达终点更新答案
        rep(i, 0, 3) {
            int x = cur.x + dir[i][0];
            int y = cur.y + dir[i][1];
            if (check(x, y) && i!=cur.di) { //若方向不同则判断
                int d = cur.w + a[x][y];
                if (dis2[x][y][i] > d) {
                    dis2[x][y][i] = d;
                    q.push(node{x, y, d, i});
                }
            }
        }
    }
    return ans==LLONG_MAX?-1:ans;
}
signed main() {
    int cnt = 0;
    while (cin >> n >> m >> r1 >> c1 >> r2 >> c2) {
        rep(i, 1, n) {
            rep(j, 1, m) {
                string s;
                cin >> s;
                if (s == "*") a[i][j] = 0; //障碍设为0
                else a[i][j] = stoll(s); //可走的格子为数字
            }
        }
        cout << "Case " << ++cnt << ": " << dj1() << " "<< dj2() << endl;
    }
}




四.小结

算是板子题,开始想的贪心,后来还是得弄四个方向的最短路才行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值