UVA11374 Airport express

UVA11374 Airport express

题目链接 https://www.luogu.com.cn/problem/UVA11374

 题意:无向图中n个点给定起点s和终点e求最短路,不同的是有m条边是普通的,另外k条边中最多只能选1条。需要输出最短路的路径,长度,若用到了k条边中的某一条,则需要输出是在哪个点用到的, 否则输出"Ticket Not Used" 格式具体看题目。

思路:先在只有m条边的图中从起点和终点分别两次dijkstra, 求出到其他点的最短路分别为dis1[], dis[]。由于k条边中只能选1条,所以枚举其中的每一条边,这里假设选了u, v, 则最短路为dis1[u] + w(u, v) + dis[v],遍历求出最小值即可, 不要忘记和不使用k条边的最短路即dis1[e]比较。路径通过pre[]数组记录每个点的前驱来得到。

Note.多组数据,每组数据间需要有空行,且行末不能有多余空格。

// Decline is inevitable
// Romance will last forever
#include 
using namespace std;
#define mst(a, x) memset(a, x, sizeof(a))
#define INF 0x3f3f3f3f
const int maxn = 5e2 + 10;
const int maxm = 4e3 + 10;
int n, e, m, k, head[maxn], cnt;  //建图
bool vis[maxn];
int dis1[maxn], dis[maxn];     //dis1记录起点到每个点最短路 dis记录终点到每个点最短路
int pre1[maxn], pre[maxn];     //pre1记录起点跑最短路的每个点的前驱, pre则为终点
stack sta;     //把pre1数组压入栈中 方便输出路径
struct Edge {
    int to, dis, next;
}edge[maxm];
struct node {
    int dis;
    int pos;
    node(int dis = 0, int pos = 0) : dis(dis), pos(pos) {}
    bool operator < (const node &x)const {
        return dis > x.dis;
    }
};
void add_edge(int u, int v, int w) {
    cnt++;
    edge[cnt].to = v;
    edge[cnt].dis = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
}
priority_queue q;
void dijkstra(int s) {  //dijkstra 求以s的起点的最短路
    mst(pre, -1);
    mst(vis, false);
    mst(dis, 0x3f);
    while(!q.empty()) q.pop();
    dis[s] = 0;
    q.push(node(0, s));
    while(!q.empty()) {
        node tmp = q.top();
        q.pop();
        int x = tmp.pos;
        if(vis[x]) continue;
        vis[x] = 1;
        for(int i = head[x]; i; i = edge[i].next) {
            int y = edge[i].to;
            if(dis[y] > dis[x] + edge[i].dis)
                dis[y] = dis[x] + edge[i].dis, pre[y] = x ;
            if(!vis[y])
                q.push(node(dis[y], y));
        }
    }
}
void solve() {
    int s;
    int t = 0;
    while(scanf("%d%d%d", &n, &s, &e) !=EOF) {
        if(t++) cout << "\n";
        cnt = 0;
        mst(head, 0);
        mst(dis1, 0x3f);
        mst(pre1, 0);
    cin >> m;
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    int ans = INF;
    bool flag = true;
    dijkstra(s);
    for(int i = 1; i <= n; i++)
        dis1[i] = dis[i], pre1[i] = pre[i];
    dijkstra(e);
    ans = dis1[e];
    cin >> k;
    int c = 0, d = 0;
    for(int i = 0; i < k; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        if(dis1[u] + dis[v] + w < ans) {
            c = u, d = v;
            flag = false;
            ans = dis1[u] + dis[v] + w;
        }
        if(dis1[v] + dis[u] + w < ans) {
            flag = false;
            c = v, d = u;
            ans = dis1[v] + dis[u] + w;
        }
    }
    if(flag) {
        int x = s;
        while(1) {
            if(x == e) {
                cout << x << "\n";
                break;
            }
            cout << x << ' ';
            x = pre[x];
        }
        cout << "Ticket Not Used\n";
        cout << ans << "\n";
    }
    else {
        int f = c;
        sta.push(c);
        while(pre1[c] != -1) {
            sta.push(pre1[c]);
            c = pre1[c];
        }
        while(!sta.empty())
            cout << sta.top() << ' ', sta.pop();
        while(1){
            if(d == e) {
                cout << d << "\n";
                break;
            }
            cout << d << ' ';
            d = pre[d];
        }
        cout << f << "\n";
        cout << ans << "\n";
    }
    }
}
signed main() {
    solve();
    return 0;
}

你可能感兴趣的:(图论,蓝书,算法)