POJ 3463 Sightseeing (求最短路和次短路數量)
阿新 • • 發佈:2018-12-27
原題地址: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;
}