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;
}






posted on 2017-04-23 12:20  ljbguanli  阅读(330)  评论(0编辑  收藏  举报