SRM 624 D1L2:DrivingPlans,求解所有的最短路径

题目:http://community.topcoder.com/stat?c=problem_statement&pm=13197&rd=15857

跟一般的最短路径问题不一样,本题要求所有的最短路径数,而且有0权值边,算法与Dijkstra算法有点类似,不同的的当找到一个点到源点最短路径长度时,并不标记该点为已访问点,而是加上该路径上前一个点的最短路径数, 并且标记已访问过的边,确保每条边只访问一次。关于0边的处理也要注意,基本思想就是任何一个点若与0边相连,则该点到源点的最短路径数必为无穷大,若一条最短路径上前一个点是这样的点,则后一个点也是这样的点。

代码:

#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <iostream>
#include <sstream>
#include <iomanip>

#include <bitset>
#include <string>
#include <vector>
#include <stack>
#include <deque>
#include <queue>
#include <set>
#include <map>

#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <cstring>
#include <ctime>
#include <climits>
using namespace std;

#define CHECKTIME() printf("%.2lf\n", (double)clock() / CLOCKS_PER_SEC)
typedef pair<int, int> pii;
typedef long long llong;
typedef pair<llong, llong> pll;
#define mkp make_pair

/*************** Program Begin **********************/
const int MOD = 1000000009;
const int INF = 1000000000;
int ways[2001], dist[2001];
bool visited[2001];	// 防止重复访问0边

typedef pair<int, int> Node;

class DrivingPlans {
public:
	int count(int N, vector <int> A, vector <int> B, vector <int> C) {
		int res = 0;
		int E = A.size();

		memset(ways, 0, sizeof(ways));
		ways[1] = 1;
		for (int i = 1; i <= N; i++) {
			dist[i] = INF;
		}
		dist[1] = 0;
		memset(visited, 0, sizeof(visited));

		set <Node> S;
		for (int i = 0; i < E; i++) {
			int u = A[i], v = B[i], w = C[i];
			if (0 == w) {
				ways[u] = ways[v] = -1;
			}
			if (1 == v) {
				swap(A[i], B[i]);
				swap(u, v);	
			}
			if (1 == u) {
				dist[v] = w;
				visited[i] = true;
				S.insert(mkp(w, i));
			}
		}

		while (!S.empty()) {
			int shortest = (*S.begin()).first;
			int k = (*S.begin()).second;
			S.erase(S.begin());
			int cur = B[k];
			if (shortest == dist[cur]) {	// 若该条路径为最短路径,则更新ways[]
				// update ways
				if (C[k] != 0 && ways[A[k]] != -1 && ways[cur] != -1) {
					ways[cur] += ways[A[k]];
					ways[cur] %= MOD;
				} else {
					ways[cur] = -1;
				}
			} else {
				continue;
			}

			// update
			for (int i = 0; i < E; i++) {
				if (visited[i]) {
					continue;
				}
				int u = A[i], v = B[i], w = C[i];
				if (v == cur) {
					swap(A[i], B[i]);
					swap(u, v);
				}
				if (u == cur && shortest + w <= dist[v]) {
					set <Node>::iterator it = S.find(mkp(dist[v], i));
					if (it != S.end()) {
						S.erase(it);
					}
					dist[v] = shortest + w;
					S.insert(mkp(dist[v], i));
					visited[i] = true;
				}
			}
		}
		res = ways[N];
		return res;
	}

};

/************** Program End ************************/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值