您的位置:首页 > 编程语言 > Go语言

CDOJ_1147 (最短路条数)

2015-11-18 20:03 423 查看

秋实大哥带我飞

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 InputSample 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


代码清单:
/*******************************************************************************
*** 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
){
return true;
}
}
return false;
}

void solve(){
dijkstra(dist1, sum1, 1);
dijkstra(dist2, sum2, n);
if(check()) printf("-1\n");
else printf("%lld\n", sum1
% mod);
}

int main(){
input();
solve();
exit();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm algorithm CDOJ dijkstra