DP - 打望
Posted lrw04
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP - 打望相关的知识,希望对你有一定的参考价值。
题面
【问题描述】
Mr_he 是一个求变的人,所以每天从学校机房回到家都要走不同的路径,当然劳累一天然后漫步 在新鲜的大路上,打望过往行人和车辆也是一件非常惬意的事。 那么现在已经知道,从Mr_he 的学校到家有n 个交叉路口,把他们从1..n 编号,我们认为编 号为1 的是学校,编号为2 的为家,有m 条双向大路把这些路口连接起来。 Mr_he 打算每天沿着一条不同的路径回家(如果两条路径有一条道路不同,那么我们认为这两条 路径是不同的),欣赏不同的风景。但他不想太晚回家,因此他不打算走“回头路”。换句话说,他只 沿着满足如下条件的道路(A,B)走:存在一条从B 出发回家的路径比所有从A 出发回家的路径都短。 那么你的任务是帮助Mr_he 计算一共有多少条不同的回家路径。
【输入格式】
第一行为n,m,交叉点的数目和道路的数目。
以下 m 行每行 3 个整数:a,b,d(1≤a,b≤n,1≤d≤1000000),表示有一条连接a 和b 的双向道路,长度为d。
【输出格式】
输出路径条数。这个数可能很大,请输出 mod 20080814 的结果。
【输入样例】
5 6
1 3 2
1 4 2
3 4 3
1 5 12
4 2 34
5 2 24
【输出样例】
2
【数据范围】
20%的数据:1<n≤10
50%的数据:1<n≤100
100%的数据:1<n≤1000,n-1≤m≤100000
解
重读题目,意即寻找从机房到家,结点到家的最短路程递减的路径条数。那么可以用 Dijkstra 得出所有节点到家的最短路程,再 DP 得出从机房开始的这样的路径条数。
程序
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
#define MAXN 1020
#define MAXM 200020
int to[MAXM], nxt[MAXM], hd[MAXN], ne = 0;
ll val[MAXM];
int n, m;
void _link(int u, int v, ll w) {
nxt[++ne] = hd[u];
hd[u] = ne;
to[ne] = v;
val[ne] = w;
}
void link(int u, int v, ll w) {
_link(u, v, w);
_link(v, u, w);
}
ll dist[MAXN];
bool vis[MAXN];
struct HeapNode {
int u;
ll d;
HeapNode(int u=0, ll d=0): u(u), d(d) {}
bool operator<(const HeapNode& rhs) const {
return d > rhs.d;
}
};
void dijkstra(int s) {
priority_queue<HeapNode> q;
memset(vis, false, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0;
q.push(HeapNode(s, 0));
while (!q.empty()) {
int u = q.top().u;
q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; ll w = val[i];
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
q.push(HeapNode(v, dist[v]));
}
}
}
}
#define MOD 20080814
int d[MAXN];
int dp(int u) {
if (d[u] > -1) return d[u];
// cerr << " " << u << endl;
int ans = 0;
bool flg = true;
for (int i = hd[u]; i; i = nxt[i])
if (dist[to[i]] < dist[u]) {
ans = (ans + dp(to[i])) % MOD;
flg = false;
}
if (flg) ans = 1;
return d[u] = ans;
}
int main() {
cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v;
ll w;
cin >> u >> v >> w;
link(u, v, w);
}
dijkstra(2);
// for (int i = 1; i <= n; i++) cerr << dist[i] << " "; cerr << endl;
memset(d, -1, sizeof(d));
cout << dp(1) << endl;
// for (int i = 1; i <= n; i++) cerr << d[i] << " "; cerr << endl;
return 0;
}
以上是关于DP - 打望的主要内容,如果未能解决你的问题,请参考以下文章
HDU4057 Rescue the Rabbit(AC自动机+状压DP)
HDU3247 Resource Archiver(AC自动机+BFS+DP)