Atcoder Beginner Contest 144 F- Fork the Road

题目链接:https://atcoder.jp/contests/abc144/tasks/abc144_f
题意:
有n个洞穴(从1到n编号),m条单向通道。每条通道由si到达ti,保证si 现在有一个人初始时在第一个洞穴,他有相等的概率走向下一个可到达的洞穴。
每通过一条通道耗费为1.设此人走到第n个洞穴的所需走的步数的期望为E。
现在可以通过破坏掉一个通道,使得E变小。破坏通道后一定要保证此人一定有一种方式可以到达第n个洞穴,否则不能够破坏任何通道。
求在破坏某条通道(可以不破坏)后的最小的E。
题解:
概率DP。
设f【x】为由第x个洞穴走到第n个洞穴的期望步数。
状态转移方程:
设len为x洞穴可到达的洞穴个数,i为可到达洞穴中的第i个。
f【x】=1/len * ∑ i = 0 l e n \sum_{i=0}^{len} i=0lenf【i】

以上已经求解出了在不破坏掉任何通道从各个洞穴走向第n个洞穴的期望步数。
为了是E变小,可以枚举所有的点后的某条边(O(n)),
从每个点的后续可走洞穴中,破坏掉f【i】最大的那个,最终结果为f【1】。(O(n+m))
取其中最小的f【1】即为最终答案。
AC代码:

#include 
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;
}

欢迎评论!

你可能感兴趣的:(动态规划—dp,Atcoder,Beginner,Contest,144,F,概率DP)