题目链接:https://atcoder.jp/contests/abc144/tasks/abc144_f
题意:
有n个洞穴(从1到n编号),m条单向通道。每条通道由si到达ti,保证si<ti。
现在有一个人初始时在第一个洞穴,他有相等的概率走向下一个可到达的洞穴。
每通过一条通道耗费为1.设此人走到第n个洞穴的所需走的步数的期望为E。
现在可以通过破坏掉一个通道,使得E变小。破坏通道后一定要保证此人一定有一种方式可以到达第n个洞穴,否则不能够破坏任何通道。
求在破坏某条通道(可以不破坏)后的最小的E。
题解:
概率DP。
设f【x】为由第x个洞穴走到第n个洞穴的期望步数。
状态转移方程:
设len为x洞穴可到达的洞穴个数,i为可到达洞穴中的第i个。
f【x】=1/len * f【i】
以上已经求解出了在不破坏掉任何通道从各个洞穴走向第n个洞穴的期望步数。
为了是E变小,可以枚举所有的点后的某条边(O(n)),
从每个点的后续可走洞穴中,破坏掉f【i】最大的那个,最终结果为f【1】。(O(n+m))
取其中最小的f【1】即为最终答案。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=607;
const int inf=1e9;
int n,m,a[maxn*maxn],b[maxn*maxn];
vector <int> vec[maxn];
double f[maxn],ans;
double dp(int p)
{
for(int i=1;i<=n;i++)
f[i]=0;
f[n]=0;
for(int i=n-1;i>=1;i--)
{
int len=vec[i].size();
if(p==i&&len==1)
{
f[i]=inf;
continue;
}
double t=1.0/(len-(p==i)),mx=0;
for(int j=0;j<len;j++)
{
int v=vec[i][j];
mx=max(mx,(f[v]+1)*t);
f[i]+=(f[v]+1)*t;
}
if(p==i) f[i]-=mx;
}
return f[1];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i]>>b[i];
vec[a[i]].push_back(b[i]);
}
ans=dp(0);
for(int i=1;i<=n;i++)
ans=min(ans,dp(i));
cout<<fixed<<setprecision(9)<<ans<<"\n";
return 0;
}
欢迎评论!