GDKOI2016 Day1 T2 不稳定的传送门

来源:互联网 发布:花生日记app淘宝 编辑:程序博客网 时间:2024/06/05 17:14

T2 不稳定的传送门

给出N个点,点与点之间由单向边连接,每条边有使用的代价和成功的概率,若失败则返回出发点。每条边只能使用一次。数据保证没有环,点i与i+1之间一定有一条成功概率为100%的边,求从1走到N的最小期望花费。

神奇的概率题。设F[i]表示从i到N的最小期望,对于从i出去的确定顺序的每一条边,F[i]=p1F[to1]+w1+(1p1)(p2F[to2]+w2)+(1p1)(1p2)(p3F[to3]+w3)....
考虑化简这个这个式子,设pif[toi]+wi=xi,(1pi)=yi,则原式=x1+y1x2+y1y2x3+...
对于相邻的两条边i,j。设Si表示先放i的期望,Sj表示先放j的期望,则
Si=x1+y1x2+y1y2x3+...+y1.....yi1xi+y1...yi1yixj
Sj=x1+y1x2+y1y2x3+...+y1.....yi1xj+y1...yi1yjxi
消去相同项,Si=xi+yixj,Sj=xj+yjxi
如果先放i比先放j更优的话,则
xi+yixj<xj+yjxi
yixjxj<yjxixi
(yi1)xj<(yj1)xi
(yi1)/xi<(yj1)/xj
代入原项,得
(1pi1)/(pif[toi]+wi)<(1pj1)/(pjf[toj]+wj)
pi/(pif[toi]+wi)>pj/(pjf[toj]+wj)
可以证明对于不相邻的i和j,也满足这条式子。
发现等号左边只和i有关,等号右边只和j有关,于是我们可以吧这个东西排一次序,这样就得到最优顺序了。然后直接递推就好了。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define N 100005#define M 200005#define db doubleusing namespace std;struct note{    int x,y,c;db p,f;}a[M];bool cmd(note x,note y) {return x.x<y.x;}bool cmp(note x,note y) {return x.f>y.f;}db f[N];int l[N],r[N],n,m;int main() {    scanf("%d%d",&n,&m);    fo(i,1,n-1) scanf("%d",&a[i].c),a[i].x=i,a[i].y=i+1,a[i].p=1;    fo(i,n,m+n-1) scanf("%d%d%lf%d",&a[i].x,&a[i].y,&a[i].p,&a[i].c);    sort(a+1,a+m+n,cmd);    fo(i,1,m+n-1)        if (a[i].x!=a[i-1].x) r[a[i-1].x]=i-1,l[a[i].x]=i;    r[a[n+m-1].x]=n+m-1;    fd(i,n-1,1) {        fo(j,l[i],r[i]) a[j].f=a[j].p/(a[j].p*f[a[j].y]+a[j].c);        sort(a+l[i],a+r[i]+1,cmp);        db x=1;        fo(j,l[i],r[i]) {            f[i]=f[i]+(f[a[j].y]*a[j].p+a[j].c)*x;            x*=(1-a[j].p);        }    }    printf("%.2lf",f[1]);}
0 0
原创粉丝点击