HDU 1142 A Walk Through the Forest

传送门

最短路+记忆化搜索。
一个无向图,问你从起点到终点有多少条这样的路,该路径包含的边a->b都满足至少存在一条b到终点的路比所有a到终点的路都要短。这道题中path指边,route指路径。

这道题比较良心,说了权值都为正。首先这个条件等价于b到终点的最短路小于a到终点的最短路。那么先求所有点到终点的最短路,因为是无向图所以不用反向建边了,直接以终点为源点求最短路。

接下来从起点开始dfs,用cnt[]表示从当前点到终点的路径条数,所以当前点的路径条数等于它的所有合法邻接点的路径条数之和。这里就出现了两个动态规划的特征,最优子结构(原问题的最优解可通过子问题的最优解构造出来)和重叠子问题,所谓重叠,指的是多条支路可能汇聚于中间一点,而对于每一条路径而言,一定是简单路!(想想该路径的定义,沿着该路径走,每个点到终点的最短路的值一定越来越小)

既然意识到了重叠子问题,那么就不用重复求相同的子问题了。所以这就是记忆化搜索。另外,如果不想(会超时的)记忆化搜索,应该在每次计算当前点cnt[]之前先初始化为0,因为这个点可能已经计算过了(想象多条支路汇聚的点)。

另外,这道题说的路径完全可以不是最短路(如果是的话直接求最短路条数不就完了吗。。),比如下图:
在这里插入图片描述


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
#include <utility>
using namespace std;

const int INF = 0x3F3F3F3F;
const int MAXN = 1001;
int N, M;
vector<pair<int, int>> v[MAXN];
int d[MAXN];
bool inq[MAXN];
int cnt[MAXN];                  // 某点到终点(2)有多少条路

void init()
{
	for (int i = 1; i <= N; i++) v[i].clear();
	memset(cnt, 0, sizeof cnt);
	//cnt[2] = 1;                 // 终点到终点有1条路
}

void spfa(int s)
{
	memset(d, 0x3F, sizeof d);
	memset(inq, 0, sizeof inq);
	d[s] = 0;
	queue<int> q;
	q.push(s);
	inq[s] = true;
	for (; !q.empty();)
	{
		int t = q.front();
		q.pop();
		inq[t] = false;
		for (int i = 0; i < v[t].size(); i++)
		{
			int n = v[t][i].first;
			int w = v[t][i].second;
			if (d[t] + w < d[n])
			{
				d[n] = d[t] + w;
				if (!inq[n])
				{
					q.push(n);
					inq[n] = true;
				}
			}
		}
	}
}

int dfs(int s)
{
	if (s == 2) return 1;
	if (cnt[s] > 0) return cnt[s];                // 这就是记忆化搜索,若把这行改成 cnt[s]=0,会超时的
	for (int i = 0; i < v[s].size(); i++)
	{
		int n = v[s][i].first;
		if (d[n] < d[s])
			cnt[s] += dfs(n);
	}
	return cnt[s];
}

int main()
{
	int a, b, c;
	for (; ~scanf("%d", &N);)
	{
		if (!N) break;
		scanf("%d", &M);
		init();
		for (int i = 0; i < M; i++)
		{
			scanf("%d%d%d", &a, &b, &c);
			v[a].push_back(make_pair(b, c));
			v[b].push_back(make_pair(a, c));
		}
		spfa(2);
		printf("%d\n", dfs(1));
	}

	return 0;
}
posted @ 2019-04-11 00:40  CrossingOver  阅读(100)  评论(0编辑  收藏  举报