How Many Paths Are There
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1702 Accepted Submission(s): 618
Problem Description
oooccc1 is a Software Engineer who has to ride to the work place every Monday through Friday. For a long period, he went to office with the shortest path because he loves to sleep late…Time goes by, he find that he should have some changes as you could see, always riding with the same path is boring.
One day, oooccc1 got an idea! Why could I take another path? Tired at all the tasks he got, he got no time to carry it out. As a best friend of his, you’re going to help him!
Since oooccc1 is now getting up earlier, he is glad to take those paths, which are a little longer than the shortest one. To be precisely, you are going to find all the second shortest paths.
You would be given a directed graph G, together with the start point S which stands for oooccc’1 his house and target point E presents his office. And there is no cycle in the graph. Your task is to tell him how long are these paths and how many there are.
One day, oooccc1 got an idea! Why could I take another path? Tired at all the tasks he got, he got no time to carry it out. As a best friend of his, you’re going to help him!
Since oooccc1 is now getting up earlier, he is glad to take those paths, which are a little longer than the shortest one. To be precisely, you are going to find all the second shortest paths.
You would be given a directed graph G, together with the start point S which stands for oooccc’1 his house and target point E presents his office. And there is no cycle in the graph. Your task is to tell him how long are these paths and how many there are.
Input
There are some cases. Proceed till the end of file.
The first line of each case is three integers N, M, S, E (3 <= N <= 50, 0 <= S , E <N)
N stands for the nodes in that graph, M stands for the number of edges, S stands for the start point, and E stands for the end point.
Then M lines follows to describe the edges: x y w. x stands for the start point, and y stands for another point, w stands for the length between x and y.
All the nodes are marked from 0 to N-1.
The first line of each case is three integers N, M, S, E (3 <= N <= 50, 0 <= S , E <N)
N stands for the nodes in that graph, M stands for the number of edges, S stands for the start point, and E stands for the end point.
Then M lines follows to describe the edges: x y w. x stands for the start point, and y stands for another point, w stands for the length between x and y.
All the nodes are marked from 0 to N-1.
Output
For each case,please output the length and count for those second shortest paths in one line. Separate them with a single space.
Sample Input
3 3 0 2 0 2 5 0 1 4 1 2 2
Sample Output
6 1
求次短路的过程其实是建立在求最短路的基础上的,就是在求最短路的同时,用另一个数组来记录次短路
过程中有个两种情况
1. 该点的最短路可以被更1新为更小的值,那么它原来的那个值就可以被更新为次短路的值
2. 该点的最短路不可以被更新,但是到该点的值比次短路的要小,那么介于次短和最短的,要把它更新为次短
但是题目要求记下有多少不同的路径数
使用一个 dp数组 dp[i][1]表示最短路到 i 点的方案数量 ,dp[i][2]表示到 i 点次短路的方案数量
那么在更新最短路距离的时候 dp[i][1]要更新为到它上一节点的方案数。
在更新了次短路距离的时候也是如此,这两种情况就可以在进行上面的两种情况的时候同时进行
还有两种情况
1.当前又出现了与最短路距离相等的路径,那么 dp[i][1] += dp[前一节点][mark]
2.当前又出现了与次短路距离相等的路径,那么 dp[i][2] += dp[前一节点][mark] // mark 表示最短路,2表示次短路
所以总共是4种情况,代码如下
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
#define maxn 100
#define inf 999999999
struct edge{
int to,val;
};
vector<edge>e[maxn];
int dis[maxn][3],dp[maxn][3],vis[maxn][3];
int n,m;
struct node{
int to,val,mark; // mark 1 表示最短路 2 表示次短路
bool operator < (const node &a) const{ //优先队列,取权值最小的,其次是下标最小
if(a.val != val){
return a.val < val;
}
return a.to < to;
}
};
void Dijkstra(int start,int end){
for(int i = 0;i <= n;i++){
dis[i][1] = dis[i][2] = inf;
}
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
priority_queue<node>Q;
node p,q;
dis[start][1] = 0; // dis[][1]表示最短路距离 dis[][2]表示次短路距离
dp[start][1] = 1; // dp[][1]表示最短路的路径数 dp[][2]表示次短路路径数
p.val = 0,p.mark = 1,p.to = start;
Q.push(p);
while(!Q.empty()){
p = Q.top();
Q.pop();
if(vis[p.to][p.mark])
continue;
vis[p.to][p.mark] = 1;
for(int i = 0;i < e[p.to].size();i++){
int v = e[p.to][i].to;
int w = e[p.to][i].val;
if(!vis[v][1] && p.val + w < dis[v][1]){ //如果该点的最短路距离可以被更新
if(dis[v][1] != inf){ //如果它不是 inf 那么它原来的距离可以更新为次短路
q.val = dis[v][1];
q.to = v;
q.mark = 2;
dis[v][2] = dis[v][1];
dp[v][2] = dp[v][1]; //并且次短路的路径数可以直接继承
Q.push(q);
}
dis[v][1] = p.val + w;
dp[v][1] = dp[p.to][p.mark]; //更新最短路
q.val = dis[v][1];
q.to = v;
q.mark = 1;
Q.push(q);
}else if(!vis[v][1] && p.val + w == dis[v][1]){ //如果最短距离相同,表示找到了多条路径
dp[v][1] += dp[p.to][p.mark]; //那么路径数要加
}else if(!vis[v][2] && p.val + w < dis[v][2]){ //如果它不小于最短路,但他小于次短路,那么更新次短路
dis[v][2] = p.val + w;
dp[v][2] = dp[p.to][p.mark];
q.val = dis[v][2];
q.to = v;
q.mark = 2;
Q.push(q);
}else if(!vis[v][2] && p.val + w == dis[v][2]){ //如果它与次短路距离相同,那么更新次短路路径数
dp[v][2] += dp[p.to][p.mark];
}
}
}
}
int main(){
int start,end,u,v,w;
while(scanf("%d %d %d %d",&n,&m,&start,&end) != EOF){
for(int i = 0;i <= n;i++)
e[i].clear();
for(int i = 1;i <= m;i++){
scanf("%d %d %d",&u,&v,&w);
edge tmp;
tmp.to = v;
tmp.val = w;
e[u].push_back(tmp);
}
Dijkstra(start,end);
printf("%d %d\n",dis[end][2],dp[end][2]);
}
return 0;
}