UVA 10917 Walk Through the Forest(Dijkstra+DAG动态规划)
题意:gbn近期打算穿过一个森林。可是他比較傲娇,于是他决定仅仅走一些特殊的道路。他打算仅仅沿着满足例如以下条件的(A,B)道路走:存在一条从B出发回家的路,比全部从A出发回家的路径都短。你的任务是计算一共同拥有多少条不同的回家路径。
当中起点的编号为1,终点的编号为2.
思路:首先从终点Dijkstra一次。求出每一个点u回家的最短路长度。那么相当于创建了一个新图。当d[B]<d[A]时有一条A指向B的有向边,则题目的目标就是求出起点到终点的路径条数。由于这个图是DAG,能够用动态规划求解。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #define eps 1e-6 #define LL long long using namespace std; const int maxn = 1000 + 5; const int INF = 100000000; int n, m; //Dijkstra struct Edge { int from, to, dist; Edge(int u = 0, int v = 0, int d = 0) : from(u), to(v), dist(d) { } }; struct HeapNode { ///用到的优先队列的结点 int d, u; bool operator < (const HeapNode& rhs) const { return d > rhs.d; } }; struct Dijkstra { int n, m; //点数和边数 vector<Edge> edges; //边列表 vector<int> G[maxn]; //每一个节点出发的边编号 bool done[maxn]; //是否已经永久编号 int d[maxn]; //s到各个点的距离 int p[maxn]; //最短路中的上一条边 LL dp[maxn]; void init(int n) { this->n = n; for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); memset(dp, -1, sizeof(dp)); } void AddEdge(int from, int to, int dist) { //假设是无向图须要调用两次 edges.push_back(Edge(from, to, dist)); m = edges.size(); G[from].push_back(m-1); } void dijkstra(int s) { //求s到全部点的距离 priority_queue<HeapNode> Q; for(int i = 0; i < n; i++) d[i] = INF; d[s] = 0; memset(done, 0, sizeof(done)); Q.push((HeapNode){0, s}); while(!Q.empty()) { HeapNode x = Q.top(); Q.pop(); int u = x.u; if(done[u]) continue; done[u] = true; for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if(d[e.to] > d[u] + e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i]; Q.push((HeapNode){d[e.to], e.to}); } } } } LL DP(int S) { if(S == 1) return 1; if(dp[S] != -1) return dp[S]; else { dp[S] = 0; int sz = G[S].size(); for(int i = 0; i < sz; i++) { Edge e = edges[G[S][i]]; if(d[e.to]<d[S]) dp[S] += DP(e.to); } } return dp[S]; } } Dij; void init() { Dij.init(n); int u, v, d; for(int i = 0; i < m; i++) { scanf("%d%d%d", &u, &v, &d); u--; v--; Dij.AddEdge(u, v, d); Dij.AddEdge(v, u, d); } Dij.dijkstra(1); } void solve() { cout << Dij.DP(0) << endl; } int main() { //freopen("input.txt", "r", stdin); while(scanf("%d%d", &n, &m) == 2 && n) { init(); solve(); } return 0; }