GDKOI2016Day1第二题 不稳定的传送门 解题报告

GDKOI2016Day1第二题T2题解

  • 题目描述略

  • 样例解释:

    首先,数组 Fi 表示由i至n的最优期望方案的值。
    先将i连向i+1的那条边看成一条费用为 W ,成功传送的概率为 P , P =1(100%),门的终点为 U , U = i +1
    当我们做到第 i 个点时,我们可以通过已做完的点 j Fj 的值转移过来。
    假设做到了第 i 个点,考虑门的使用顺序,对门的顺序进行一次全排列,选最优方案,便是 Fi 的值。
    用样例来举例子。

    • i =4时, Fi =0
    • i =3时,只能选择一扇门,故 Fi = W1 + P1 * FU1 =30
      ( U1 =4, P1 =1, W1 =30)
    • i =2时,可以选择两扇门,第一扇是( U1 =3, P1 =1, W1 =30)、
      第二扇是( U2 =3, P2 =0.9, W2 =10)
      对这两扇门的顺序进行全排列,发现先放第二扇门更优。
      具体如下:
    对应内容 第二扇门 第一扇门
    使用此门传送的概率 1 1- P2 =0.1
    门费用 W2 =10 W1 =30
    传送的终点 U2 =3 U1 =3
    总期待费用 V V2 = W2 + P2 * FU2 =37 V1 =(1- P2 )( W1 + P1 * FU1 )=6

    Fi = F2 = V2 + V1 =36+6=43

    • i =1时,一样有两扇门可以选,第一扇是( U1 =4, P1 =0.5, W1 =30)、
      第二扇是( U2 =2, P2 =1, W2 =30)
      对这两扇门的顺序进行全排列,发现先放第一扇门更优。

    具体如下:

    对应内容 第一扇门 第二扇门
    使用此门传送的概率 1 1- P1 =0.5
    门费用 W1 =30 W2 =30
    传送的终点 U1 =4 U2 =2
    总期待费用 V V1 = W1 + P1 * FU1 =30 V2 =(1- P1 )( W2 + P2 * FU2 )=36.5

    Fi = F1 = V1 + V2 =30+36.5=66.5
    所以,答案就是66.5

  • 30分算法

    每个点有最多不超过5扇门,枚举门的使用顺序,选最优答案即可。

  • 100分算法

    • 可以枚举门的使用顺序,那么能不能通过某种方式求出最优的使用顺序呢?

    • 不妨先将一种门(共k扇门)的使用顺序的期望值列出来。
      Fi = W1 + P1 FU1 +(1- P1 )( W2 + P2 FU2 +(1- P2 )( W3 + P3 FU3 +(1- P3 )(……)))
      设 1- Pi = Vi Wi + Pi FUi = Ki
      Fi = W1 + V1 ( W2 + V2 ( W3 + V3 (…)))
      将这个式子拆括号
      Fi = W1 + V1 W2 + V1 V2 W3 + V1 V2 V3 W4 …+ V1 V2 ~ Vk2 Vk1 Wk

    • 假设已经放了前q扇门,且为最优解,接下来考虑该放哪扇门才是最优的。假设现在有两扇门i,j可选择,如果先放第i扇门更优则一定满足
      W1 + V1 W2 + V1 V2 W3 + V1 V2 V3 W4 …+ V1 V2 ~ Vq Wi + V1 V2 ~ Vq Vi Wj
      < W1 + V1 W2 + V1 V2 W3 + V1 V2 V3 W4 …+ V1 V2 ~ Vq Wj + V1 V2 ~ Vq Vj Wi

      化简得

      Wi + Vi Wj < Wj + Vj Wi

      Wi - Vj Wi < Wj - Vi Wj

      (1- Vj ) Wi <(1- Vi ) Wj

      (1Vj)Wj < (1Vj)Wj

      PjWj+VjWj < PiWi+ViWi

      PiWi+ViWi > PjWj+VjWj

    • 此时,含 i j 的项全部移到了一边,也就是说上述不等式成立时,先放 i 比先放 j 更优,且如果 i j 优, j l 优,则 i l 优,具有了传递性

    • 现在只需按照 PiWi+ViWi 从大到小排序,便可以得到最优的门的使用顺序了.

  • Code(Pascal)

var
    f,bl,px:array[0..1000000] of extended;
    door:array[0..1000000,1..3] of longint;
    en:array[0..1000000] of longint;
    n,m,j,k,l,i,o,p:longint;
    dqbl:extended;
procedure qsort(l,r:longint);
    var
        i,j,m:longint;
    begin
        i:=l;
        j:=r;
        m:=door[(l+r) div 2,1];
        repeat
            while door[i,1]do inc(i);
            while door[j,1]>m do dec(J);
            IF i<=j then
            begin
                door[0]:=door[i];
                door[i]:=door[j];
                door[j]:=door[0];
                bl[0]:=bl[i];
                bl[i]:=bl[j];
                bl[j]:=bl[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if lthen qsort(l,j);
        if ithen qsort(i,r);
    end;
procedure kp(l,r:longint);
    var
        i,j:longint;
        m:extended;
    begin
        i:=l;
        j:=r;
        m:=px[(l+r) div 2]/bl[(l+r) div 2];
        repeat
            while px[i]/bl[i]do inc(i);
            while px[j]/bl[j]>m do dec(j);
            if i<=j then
            begin
                px[0]:=px[i];
                px[i]:=px[j];
                px[j]:=px[0];
                bl[0]:=bl[i];
                bl[i]:=bl[j];
                bl[j]:=bl[0];
                door[0]:=door[i];
                door[i]:=door[j];
                door[j]:=door[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if lthen kp(l,j);
        if ithen kp(i,r);
    end;
begin
    assign(input,'portal.in'); reset(input);
    assign(output,'portal.out'); rewrite(output);
    readln(n,m);
    for i:=1 to n-1 do
    begin
        read(p);
        door[i,1]:=i;
        door[i,2]:=i+1;
        door[i,3]:=p;
        bl[i]:=1;
        inc(en[i]);
    end;
    for i:=1 to m do
    begin
        readln(door[i+n-1,1],door[i+n-1,2],bl[i+n-1],door[i+n-1,3]);
        inc(en[door[i+n-1,1]]);
    end;
    qsort(1,n+m-1);
    for i:=2 to n do
    en[i]:=EN[I-1]+EN[I];
    en[0]:=0;
    f[n]:=0;
    for i:=n-1 downto 1 do
    begin
        for l:=en[i-1]+1 to en[i] do
        px[l]:=(door[l,3]+bl[l]*f[door[l,2]]);
        kp(en[i-1]+1,en[i]);
        f[i]:=0;
        for l:=en[i] downto en[i-1]+1 do
        f[i]:=f[i]*(1-bl[l])+px[l];
    end;
    writeln(f[1]:0:2);
    close(input);
    close(output);
end.

你可能感兴趣的:(贪心,概率与期望)