POJ 3463 Sightseeing (求最短路和次短路数量)

原题地址:http://poj.org/problem?id=3463
题意:给出一张有向图,再给出一个起点和一个终点,询问你从起点到终点的最短距离的和次短距离的边(这里要求次短距离和最短距离相差1)有几条.

思路;只要开一个cnt数组记录边的数量,dis数组记录最短路和次短路的值,然后对每一次是否可以进行松弛进行4次判断即可.

#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
int n, m, t;
struct edge {
    int v, w, nxt;
} e[maxn];
int ecnt ;
int head[maxn];
void init_head() {
    ecnt = 0;
    CLR(head, -1);
}
void add_edge(int u, int v, int w) {
    e[ecnt].v = v;
    e[ecnt].w = w;
    e[ecnt].nxt = head[u];
    head[u] = ecnt++;
}
int start, last;
int cnt[maxn][2];//计算路径数量
int dis[maxn][2];//记录最短路,次短路距离的
//0 表示最短路,1表示次短路
struct node {
    int v, flag; //v表示当前位于哪个顶点,flag标记是最短路还是次短路
    bool operator <(const node &a)const {
        return dis[v][flag] > dis[a.v][a.flag];
    }
    node() {}
    node(int v, int flag): v(v), flag(flag) {}
};
int vis[maxn][2];
int dij() {
    priority_queue<node>q;
    CLR(vis, 0);
    CLR(dis, 0x3f);
    CLR(cnt, 0);
    q.push(node(start, 0));
    dis[start][0] = 0;
    cnt[start][0] = 1;
    while(!q.empty()) {
        int u = q.top().v;
        int flag = q.top().flag;
        q.pop();
        if(vis[u][flag]) continue;
        vis[u][flag] = 1;
        for(int i = head[u]; ~i; i = e[i].nxt) {
            int v = e[i].v;
            if(dis[v][0] > dis[u][flag] + e[i].w) {//这里分四种情况分类讨论
                if(dis[v][0] != INF) {//当前值比最短路小,不是特别懂这里为什么要加if
                    dis[v][1] = dis[v][0];
                    cnt[v][1] = cnt[v][0];
                    q.push(node(v, 1));
                }
                dis[v][0] = dis[u][flag] + e[i].w;
                cnt[v][0] = cnt[u][flag];
                q.push(node(v, 0));

            } else if(dis[v][0] == dis[u][flag] + e[i].w) {//当前值和最短路相同
                cnt[v][0] += cnt[u][flag];
            } else if(dis[v][1] > dis[u][flag] + e[i].w) {//当前比次短路小
                dis[v][1] = dis[u][flag] + e[i].w;
                cnt[v][1] = cnt[u][flag];
                q.push(node(v, 1));
            } else if(dis[v][1] == dis[u][flag] + e[i].w) {//当前值和次短路相同
                cnt[v][1] += cnt[u][flag];
            }
        }
    }
    int num = cnt[last][0];
    if(dis[last][1] - 1 == dis[last][0]) num += cnt[last][1];
    return num;
}
int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        init_head();
        for(int i = 1; i <= m; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add_edge(u, v, w);
        }
        scanf("%d%d", &start, &last);
        printf("%d\n", dij());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81298546
今日推荐