题意实际上是在原图中对于一条边(a,b)如果d[a] > d[b]则在新图中连b->a的一条边。
最后求有向图的路径总数。
用dp实现。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 1005, maxm = maxn * maxn, inf = 1e9; struct node { int u, d; bool operator < (const node& rhs) const { return d > rhs.d; } }; priority_queue<node> q; int n, m, tot; int h[maxn], done[maxn], dis[maxn], vis[maxn], d[maxn]; struct edge { int v, next, w; }a[maxm], a2[maxm]; int h2[maxn]; int tot2; void add(int x, int y, int z) { a[tot].v = y; a[tot].w = z; a[tot].next = h[x]; h[x] = tot++; } void add2(int x, int y, int z) { a2[tot2].v = y; a2[tot2].w = z; a2[tot2].next = h2[x]; h2[x] = tot2++; } int dp(int u) { if (vis[u]) return d[u]; vis[u] = 1; if (u == 2) return d[2] = 1; d[u] = 0; for (int i = h2[u]; ~i; i = a2[i].next) { int v = a2[i].v; d[u] += dp(v); } return d[u]; } int main() { // freopen("uva10917.in","r",stdin); while (scanf("%d%d", &n, &m) && n && m) { memset(h, -1, sizeof h); tot = 0; for (int i = 1; i <= m; i++) { int x, y, z; scanf("%d%d%d", &x, &y, &z); add(x, y, z); add(y, x, z); } for (int i = 1; i <= n; i++) dis[i] = inf; dis[2] = 0; q.push((node){2, 0});//题目中说2是这个人的家,也就是终点 memset(done, 0 ,sizeof done); while (!q.empty()) { node x = q.top(); q.pop(); int u = x.u; if (done[u]) continue; done[u] = 1; for (int i = h[u]; ~i; i = a[i].next) { int v = a[i].v; if (dis[u] + a[i].w < dis[v]) { dis[v] = dis[u] + a[i].w; q.push((node){v,dis[v]}); } } } memset(h2, -1, sizeof h2); tot2 = 0; memset(vis, 0, sizeof vis); memset(d, 0, sizeof d); for (int i = 1; i <= n; i++) for (int j = h[i]; ~j; j = a[j].next) { int v = a[j].v; if (dis[i] < dis[v]) add2(v, i, a[j].w);//把新图搞出来 } printf("%d ", dp(1)); } return 0; }