题解:AT_arc016_4 [ARC016D] 軍艦ゲーム
更好的阅读体验
停止学习没用的算法。去做点题。学习如何使用二分查找。
假设
首先我们不难设计 dp:
位于点
容易发现第二部分的转移是萌萌的,因为图是 DAG,直接转移没有后效性。但是第一部分让转移出现了后效性。
我们这样做:我们给
然后我们发现
我们要求的就是
那么这道题就做完了,复杂度
#include<bits/stdc++.h>
#define endl '\n'
#define N 106
using namespace std;
int n,m,h,a[N],deg[N],t[N]; double f[N][N];
vector<int> rG[N];
int check(double mid)
{
queue<int> q;
for(int i=1;i<=n;i++)
for(int j=1;j<=h;j++)f[i][j]=0;
for(int i=1;i<=n;i++)
if(!(t[i]=deg[i])) {q.push(i); for(int j=1;j<=h;j++)f[i][j]=(i==n?0:h-j+mid);}
while(q.size())
{
int u=q.front(); q.pop();
if(u!=1)for(int i=1;i<=h;i++)
f[u][i]=min(f[u][i],h-i+mid);
for(int v:rG[u])
{
for(int i=1;i<=h;i++)
f[v][i]=(i<=a[u]?(h-i+mid):(f[v][i]+(f[u][i-a[u]]+1)/deg[v]));
t[v]--; if(!t[v])q.push(v);
}
}
return f[1][h]<mid;
}
main()
{
scanf("%d%d%d",&n,&m,&h);
for(int i=1,u,v;i<=m;i++)
scanf("%d%d",&u,&v),rG[v].push_back(u),deg[u]++;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
check(5);
double l=0,r=1e7;
while(r-l>1e-8)
{
double mid=(l+r)/2;
if(check(mid))r=mid; else l=mid;
}
if(l>1e6)printf("-1\n");
else printf("%.8lf\n",l);
return 0;
}