Atcoder Beginner Contest 144 F- Fork the Road

題目鏈接: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 * i=0len\sum_{i=0}^{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;
}

歡迎評論!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章