1. 程式人生 > >【bzoj4720】[Noip2016]換教室 期望dp+最短路

【bzoj4720】[Noip2016]換教室 期望dp+最短路

\n 課程 情況 memset 輸入 main 好的 can 結果

Description

對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。在可以選擇的課程中,有2n節

課程安排在n個時間段上。在第i(1≤i≤n)個時間段上,兩節內容相同的課程同時在不同的地點進行,其中,牛牛預先

被安排在教室ci上課,而另一節課程在教室di進行。在不提交任何申請的情況下,學生們需要按時間段的順序依次完

成所有的n節安排好的課程。如果學生想更換第i節課程的教室,則需要提出申請。若申請通過,學生就可以在第i個

時間段去教室di上課,否則仍然在教室ci上課。由於更換教室的需求太多,申請不一定能獲得通過。通過計算,牛牛

發現申請更換第i節課程的教室時,申請被通過的概率是一個已知的實數ki,並且對於不同課程的申請,被通過的概率

是互相獨立的。學校規定,所有的申請只能在學期開始前一次性提交,並且每個人只能選擇至多m節課程進行申請。

這意味著牛牛必須一次性決定是否申請更換每節課的教室,而不能根據某些課程的申請結果來決定其他課程是否申

請;牛牛可以申請自己最希望更換教室的m門課程,也可以不用完這m個申請的機會,甚至可以一門課程都不申請。因

為不同的課程可能會被安排在不同的教室進行,所以牛牛需要利用課間時間從一間教室趕到另一間教室。牛牛所在

的大學有v個教室,有e條道路。每條道路連接兩間教室,並且是可以雙向通行的。由於道路的長度和擁堵程度不同,

通過不同的道路耗費的體力可能會有所不同。當第i(1≤i≤n-1)節課結束後,牛牛就會從這節課的教室出發,選擇一

條耗費體力最少的路徑前往下一節課的教室。現在牛牛想知道,申請哪幾門課程可以使他因在教室間移動耗費的體

力值的總和的期望值最小,請你幫他求出這個最小值。

Input

第一行四個整數n,m,v,e。n表示這個學期內的時間段的數量;m表示牛牛最多可以申請更換多少節課程的教室;

v表示牛牛學校裏教室的數量;e表示牛牛的學校裏道路的數量。

第二行n個正整數,第i(1≤i≤n)個正整數表示c,,即第i個時間段牛牛被安排上課的教室;保證1≤ci≤v。

第三行n個正整數,第i(1≤i≤n)個正整數表示di,即第i個時間段另一間上同樣課程的教室;保證1≤di≤v。

第四行n個實數,第i(1≤i≤n)個實數表示ki,即牛牛申請在第i個時間段更換教室獲得通過的概率。保證0≤ki≤1。

接下來e行,每行三個正整數aj,bj,wj,表示有一條雙向道路連接教室aj,bj,通過這條道路需要耗費的體力值是Wj;

保證1≤aj,bj≤v,1≤wj≤100。

保證1≤n≤2000,0≤m≤2000,1≤v≤300,0≤e≤90000。

保證通過學校裏的道路,從任何一間教室出發,都能到達其他所有的教室。

保證輸入的實數最多包含3位小數。

Output

輸出一行,包含一個實數,四舎五入精確到小數點後恰好2位,表示答案。你的

輸出必須和標準輸出完全一樣才算正確。

測試數據保證四舎五入後的答案和準確答案的差的絕對值不大於4*10^-3。(如果你不知道什麽是浮點誤差,這段話

可以理解為:對於大多數的算法,你可以正常地使用浮點數類型而不用對它進行特殊的處理)

Sample Input

3 2 3 3
2 1 2
1 2 1
0.8 0.2 0.5
1 2 5
1 3 3
2 3 1

Sample Output

2.80

Sol

noip這道思維難度幾乎沒有的期望dp算是道入門題吧。。。

先floyd最短路,然後\(f[i][j][0/1]\)表示第i個時刻,一共申請了j次,這次申請成不成功的期望值,轉移分類討論如下:

這次不換:從上次換了沒成功與上次沒換轉移過來

這次換:從上次換了沒成功且這次換了沒成功,上次換了成功且這次換了沒成功,上次沒換且這次成功,上次沒換且這次沒成功轉移而來。(太長了qwq)

Code

#include <bits/stdc++.h>
using namespace std;
int N,M,n,m,d[305][305],a[2005],b[2005],x,y,z;double f[2005][2005][2],ans=2147483647,p[2005];
int main()
{
    scanf("%d%d%d%d",&N,&M,&n,&m);memset(d,0x3f,sizeof(d));
    for(int i=1;i<=N;i++) for(int j=0;j<=M;j++) for(int k=0;k<=1;k++) f[i][j][k]=1e9;
    for(int i=1;i<=N;i++) scanf("%d",&a[i]);
    for(int i=1;i<=N;i++) scanf("%d",&b[i]);
    for(int i=1;i<=N;i++) scanf("%lf",&p[i]);
    for(int i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),d[x][y]=min(d[x][y],z),d[y][x]=d[x][y];
    for(int i=1;i<=n;i++) d[i][i]=0;
    for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    f[1][0][0]=f[1][1][1]=0;
    for(int i=2;i<=N;i++) for(int j=0;j<=i&&j<=M;j++)
    {
        f[i][j][0]=min(f[i-1][j][0]+d[a[i-1]][a[i]],f[i-1][j][1]+d[b[i-1]][a[i]]*p[i-1]+d[a[i-1]][a[i]]*(1-p[i-1]));
        if(j>0) f[i][j][1]=min(f[i-1][j-1][0]+d[a[i-1]][a[i]]*(1-p[i])+d[a[i-1]][b[i]]*p[i],f[i-1][j-1][1]+d[a[i-1]][a[i]]*(1-p[i-1])*(1-p[i])+d[a[i-1]][b[i]]*(1-p[i-1])*p[i]+d[b[i-1]][a[i]]*p[i-1]*(1-p[i])+d[b[i-1]][b[i]]*p[i-1]*p[i]);
    }
    for(int i=0;i<=M;i++) for(int j=0;j<=1;j++) ans=min(ans,f[N][i][j]);
    printf("%.2lf\n",ans);
}

【bzoj4720】[Noip2016]換教室 期望dp+最短路