题意: 随机在一个DAG上走,求1到n的路径长度的期望
>> P4316 绿豆蛙的归宿 <<
Strategy:基于拓扑的概率dp?
状态: d p [ i ] dp[i] dp[i]从i点到n点的期望路径长度
目标: d p [ 1 ] dp[1] dp[1] 从第一个点到第n个点的路径长度
边界: dp[n] = 0
合法判断: 本题无
转移方程:
d p [ c u r ] = ∑ ( d p [ t o ] + w [ c u r → t o ] ) / o u t [ c u r ] dp[cur] = \sum(dp[to] + w[cur\to to])/out[cur] dp[cur]=∑(dp[to]+w[cur→to])/out[cur]从cur选择一条路径的期望花费/选择该路径的概率
attention: 拓扑排序和记忆化搜索
双倍经验: 拓扑排序+记忆化搜索, 其中记忆化搜索比较无脑
记忆化
#include <bits/stdc++.h>
using namespace std;
#define _rep(i, a, b) for (ll i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (ll i = (a); i >= (b); --i)
#define _for(i, a, b) for (ll i = (a); i < (b); ++i)
#define _rof(i, a, b) for (ll i = (a); i > (b); --i)
#define maxm 109
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define what_is(x) cerr << #x << " is " << x << "s" << endl;
#define met(a, b) memset(a, b, sizeof(a))
#define pi acos(-1.0)
const ll maxn = 1e6 + 10;
int head[maxn], cnt, son[maxn], m, n;
db dp[maxn];
struct node{
int nxt, to, cost;
}way[maxn];
void addedge(int from, int to, int cost){
way[++cnt].cost = cost;
way[cnt].to = to;
way[cnt].nxt = head[from];
head[from] = cnt;
son[from]++;
}
db dfs(int cur){
if(cur == n || dp[cur])return dp[cur];
db sum = 0;
for(int i = head[cur];i;i = way[i].nxt){
sum += (dfs(way[i].to) + way[i].cost)/son[cur];
}
return dp[cur] = sum;
}
int main(){
ios::sync_with_stdio(0);
cin >> n >> m;
_rep(i, 1, m){
int u, v, t;
cin >> u >> v >> t;
addedge(u, v, t);
}
cout << fixed << setprecision(2) << dfs(1) << endl;
}
拓扑递推
#include <bits/stdc++.h>
using namespace std;
#define _rep(i, a, b) for (ll i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (ll i = (a); i >= (b); --i)
#define _for(i, a, b) for (ll i = (a); i < (b); ++i)
#define _rof(i, a, b) for (ll i = (a); i > (b); --i)
#define maxm 109
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define what_is(x) cerr << #x << " is " << x << "s" << endl;
#define met(a, b) memset(a, b, sizeof(a))
#define pi acos(-1.0)
const ll maxn = 1e5 + 10;
int head[maxn], cnt, out[maxn], m, n, in[maxn], a[maxn];
db dp[maxn];
struct node
{
int nxt, to, cost;
} way[maxn * 2];
void addedge(int from, int to, int cost)
{
way[++cnt].cost = cost;
way[cnt].to = to;
way[cnt].nxt = head[from];
head[from] = cnt;
out[from]++, in[to]++;
}
// db dfs(int cur){
// if(cur == n || dp[cur])return dp[cur];
// db sum = 0;
// for(int i = head[cur];i;i = way[i].nxt){
// sum += (dfs(way[i].to) + way[i].cost)/son[cur];
// }
// return dp[cur] = sum;
// }
void top()
{
queue<int> q;
int count = 0;
_rep(i, 1, n)
{
if (!in[i])
q.push(i), a[++count] = i;
}
while (!q.empty())
{
int cur = q.front();
q.pop();
for (int i = head[cur]; i; i = way[i].nxt)
{
int to = way[i].to;
in[to]--;
if (in[to] == 0)
q.push(to), a[++count] = to;
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin >> n >> m;
_rep(i, 1, m)
{
int u, v, t;
cin >> u >> v >> t;
addedge(u, v, t);
}
top();
_rev(i, n, 1)
{
if (a[i] == n)
continue;
db val = 0;
for (int j = head[a[i]]; j; j = way[j].nxt)
{
val += dp[way[j].to] + way[j].cost;
}
dp[a[i]] = val/out[a[i]];
}
cout << fixed << setprecision(2) << dp[1] << endl;
}
第一个是拓扑, 第二个是大法师