题目:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=74214#problem/B
题意:
n个点,m条无向边,求出从起点1到终点2的最短路径有几条.
思路:
先使用dijkstra求出最短路径树.
然后将d[a] < d[b] 时构成边<b, a>, 从而得到DAG, 然后可以是DP, 记忆化搜索.
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 1e9;
const int maxn = 1005;
int n, m;
struct Edge {
int u, v, c;
}road[maxn*maxn];
struct edge{
int to, c;
edge(int tt, int cc) {
to = tt;
c = cc;
}
};
typedef pair<int, int> P;
vector<edge> g[maxn];
int d[maxn];
vector<int> rd[maxn];
int dp[maxn];
void addedge(int u, int v, int c)
{
edge e = edge(v, c);
g[u].push_back(e);
e = edge(u, c);
g[v].push_back(e);
}
void dij(int s)
{
priority_queue<P, vector<P>, greater<P> > que;
fill(d, d + n + 1, INF);
d[s] = 0;
que.push(P(0, s));
while(que.size()) {
P p = que.top(); que.pop();
int v = p.second;
if(d[v] < p.first) continue;
for(int i = 0; i < g[v].size(); ++i) {
edge e = g[v][i];
if(d[e.to] > d[v] + e.c) {
d[e.to] = d[v] + e.c;
que.push(P(d[e.to], e.to));
}
}
}
}
void deal()
{
for(int i = 0; i <= n; ++i) {
rd[i].clear();
}
for(int i = 0; i < m; ++i) {
int u = road[i].u, v = road[i].v, c = road[i].c;
if(d[u] < d[v]) rd[v].push_back(u);
if(d[u] > d[v]) rd[u].push_back(v);
}
}
int dfs(int s)
{
int ans = 0;
if(dp[s] != -1) return dp[s];
for(int i = 0; i < rd[s].size(); ++i) {
ans += dfs(rd[s][i]);
}
return dp[s] = ans;
}
int main()
{
//freopen("in", "r", stdin);
while(~scanf("%d", &n), n) {
scanf("%d", &m);
for(int i = 0; i <= n; ++i) g[i].clear();
for(int i = 0; i < m; ++i) {
int u, v, c;
scanf("%d %d %d", &u, &v, &c);
road[i].u = u; road[i].v = v; road[i].c = c;
addedge(u, v, c);
}
dij(2);
deal();
memset(dp, -1, sizeof(dp));
dp[2] = 1;
int ans = dfs(1);
printf("%d\n", ans);
}
return 0;
}