題目鏈接: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;
}
歡迎評論!