秋实大哥带我飞
Time Limit: 300/100MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
然而题目和题面并没有什么关系。
给出 n 个点, m 条带权无向边,问你从 1 号点到 n 号点的最短路中有多少种走法?
Input
第一行两个数 n , m 分别表示点的个数和边的个数。( 2≤n≤2000 , 1≤m≤2000 )
接下来 m 行,每行3个数 u , v , w 表示 u 号点到 v 号点有一条距离为 w 的边。( 1≤u,v≤n , 0≤w≤100000 )
数据保证 1 号点能够到达 n 号点,点和边都可以被走多次。
Output
如果有无穷种走法,输出-1
。否则输出走法的方案数mod 1000000009
。
Sample input and output
Sample Input | Sample Output |
---|---|
4 4 1 2 1 1 3 1 2 4 1 3 4 1 | 2 |
4 4 1 2 1 1 3 1 2 4 1 3 4 0 | -1 |
Source
2015 UESTC Training for Graph Theory
分析:最短路条数问题。求最短路的条数只需要在dijkstra上面加一个数组sumt[]记录就行,sumt[v] 表示从源点 s 出发到 v 的最短路条数,当 dist[v] > dist[u] + d[u][v] 时,更新sumt[v] 的值就是 sumt[u];当 dist[v] == dist[u] + d[u][v] 时,sumt[v] += sumt[u];判断是否存在无数条最短路,即看是否存在这样的一条边(u, v),边权为 0,并且其中一条最短路经过这条边,也就是 源点 s 到 u 的最短距离 + v 到终点 t 的最短距离 == 最短路长度,因为边权为 0 的话就可以来回无限次地走。所以需要两次最短路分别计算出源点 s 到每个点的最短路、每个点到终点 t 的最短路,然后枚举每条边,即可判断是否存在无数条最短路。
题目链接: http://acm.uestc.edu.cn/#/problem/show/1147
代码清单:
分析:最短路条数问题。求最短路的条数只需要在dijkstra上面加一个数组sumt[]记录就行,sumt[v] 表示从源点 s 出发到 v 的最短路条数,当 dist[v] > dist[u] + d[u][v] 时,更新sumt[v] 的值就是 sumt[u];当 dist[v] == dist[u] + d[u][v] 时,sumt[v] += sumt[u];判断是否存在无数条最短路,即看是否存在这样的一条边(u, v),边权为 0,并且其中一条最短路经过这条边,也就是 源点 s 到 u 的最短距离 + v 到终点 t 的最短距离 == 最短路长度,因为边权为 0 的话就可以来回无限次地走。所以需要两次最短路分别计算出源点 s 到每个点的最短路、每个点到终点 t 的最短路,然后枚举每条边,即可判断是否存在无数条最短路。
题目链接: http://acm.uestc.edu.cn/#/problem/show/1147
代码清单:
/*******************************************************************************
*** problem ID : UESTC_1147.cpp
*** create time : Wed Nov 18 14:22:41 2015
*** author name : nndxy
*** author blog : http://blog.csdn.net/jhgkjhg_ugtdk77
*** author motto: never loose enthusiasm for life, life is to keep on fighting!
*******************************************************************************/
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define exit() return 0
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn = 2000 + 5;
const int maxm = 2000 + 5;
const int INF = 0x7f7f7f7f;
const ll mod = 1e9 + 9;
struct P{
int to, dis;
P() {}
P(int _to, int _dis) : to(_to), dis(_dis) {}
friend bool operator<(P a, P b) { return a.dis > b.dis; }
};
struct Edge{
int u, v, dis, next;
};
int n, m;
int a, b, c, num;
int head[maxn];
Edge edge[maxm * 2];
ll sum1[maxn], sum2[maxn];
int dist1[maxn], dist2[maxn];
void addEdge(int u, int v, int dis){
edge[num].u = u;
edge[num].v = v;
edge[num].dis = dis;
edge[num].next = head[u];
head[u] = num++;
}
void input(){
scanf("%d%d", &n, &m);
num = 0;
memset(head, -1, sizeof(head));
for(int i = 0; i < m; i++){
scanf("%d%d%d", &a, &b, &c);
addEdge(a, b, c);
addEdge(b, a, c);
}
}
void dijkstra(int dist[], ll sumt[], int s){
fill(dist + 1, dist + 1 + n, INF);
fill(sumt + 1, sumt + 1 + n, 0);
priority_queue <P> q;
while(!q.empty()) q.pop();
dist[s] = 0; sumt[s] = 1;
q.push(P(s, 0));
while(!q.empty()){
P p = q.top(); q.pop();
int u = p.to;
if(p.dis > dist[u]) continue;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(dist[v] > dist[u] + edge[i].dis){
sumt[v] = sumt[u] % mod;
dist[v] = dist[u] + edge[i].dis;
q.push(P(v, dist[v]));
}
else if(dist[v] == dist[u] + edge[i].dis){
sumt[v] = (sumt[v] + sumt[u]) % mod;
}
}
}
}
bool check(){
for(int i = 0; i < num; i++){
int u = edge[i].u;
int v = edge[i].v;
if(edge[i].dis == 0 && dist1[u] + dist2[v] == dist1[n]){
return true;
}
}
return false;
}
void solve(){
dijkstra(dist1, sum1, 1);
dijkstra(dist2, sum2, n);
if(check()) printf("-1\n");
else printf("%lld\n", sum1[n] % mod);
}
int main(){
input();
solve();
exit();
}