1. 程式人生 > >NOIP2016 DAY1 T3 換教室

NOIP2016 DAY1 T3 換教室

pan output clu strong int 情況下 esc 必須 string

換教室

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 思路: 其實這題是不會難的,只是相對來說,概率型DP題目做的比較少。 這題的題意很明顯是floyd + 概率DP。 我們只要先將每個教室間的最短路求出來,然後進行DP就行, 不過,這題的動態轉移方程式很.....惡心的。
我們設dp[i][j][0/1]為前i節課,一共申請了j次,第i次申不申請時的最小期望值,於是我們可以得到以下動態轉移方程: dp[i][j][0] = min( dp[i-1][j][0] + dist[c[i-1]][c[i]] , dp[i-1][j][1] + dist[c[i-1]][c[i]] * (1-k[i]) + dist[ d[i-1]][c[i]] * k[i]); dp[i][j][1] = min(dp[i-1][j-1][0]+dist[c[i-1]][d[i]]*k[i]+dist[c[i-1]][c[i]]*(1-k[i]) , dp[i-1][j-1][1]+dist[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dist[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dist[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dist[d[i-1]][d[i]]*k[i-1]*k[i]); 說不惡心人是假的...... 不過,如果仔細想想,其實上面的轉移方程不會難,定義好了狀態自己就能寫出來了。 接下來說一下初始化,初始化是將dp數組全部設為最大值,然後再使dp[1][0][0] = dp[1][1][1] = 0 ; 下面貼代碼,如果有問題 ,請在下面留言。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define V 320
#define N 2009
using namespace std;

int dist[V][V];  //兩點距離
int n,m,v,e;
int c[N],d[N];   //c數組 與 d數組 
double k[N];

double dp[N][N][2];   //設狀態dp[i][j][0/1]為前i個時間段中,申請了j個,第i個申不申請時的最小期望,因為此期望可以線性相加
                      //所以動態轉移方程為
//dp[i][j][0] = min(dp[i-1][j][0]+dist[c[i-1]][c[i]],dp[i-1][j][1]+dist[c[i-1]][c[i]]*(1-k[i-1])+ dist[d[i-1]][c[i]]*k[i])
//dp[i][j][1] = min(dp[i-1][j-1][0]+dist[c[i-1]][d[i]]*k[i]+dist[c[i-1]][c[i]]*(1-k[i]),dp[i-1][j-1][1]+dist[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])
  // + dist[c[i-1]][d[i]]*(1-k[i-1])*k[i] + dist[d[i-1]][c[i]]*k[i-1]*(1-k[i-1])+dist[d[i-1]][d[i]] * k[i-1]*k[i]);

int read(){                        //讀入優化 
    int x = 0;
    char ch = getchar();
    while(ch > 9 || ch < 0)ch = getchar();
    while(ch >= 0 && ch <= 9){
        x = x * 10 + ch - 0;
        ch = getchar();
    }
    return x;
}

void floyd(){
    for(int k = 1; k <= v; k++)
      for(int a = 1; a <= v; a++)
         for(int b = 1; b <= v; b++)
            dist[a][b] = min(dist[a][b],dist[a][k]+dist[k][b]);
}


void DP(){
    for(int i = 1; i <= v; i++)dist[i][i] = 0;
    for(int i = 1; i <= n; i++)
       for(int j = 0; j <= m; j++)
          dp[i][j][0] = dp[i][j][1] = 1e30;
    dp[1][0][0] = dp[1][1][1] = 0;
    for(int i = 2; i <= n; i++){
        int li = min(i,m);
        for(int j = 0; j <= li; j++){
            dp[i][j][0] = min(dp[i-1][j][0] + dist[c[i-1]][c[i]],dp[i-1][j][1]+dist[d[i-1]][c[i]]*k[i-1]+dist[c[i-1]][c[i]]*(1-k[i-1]));
            if(j == 0)continue;
            double x1 = dp[i-1][j-1][0]+dist[c[i-1]][d[i]]*k[i]+dist[c[i-1]][c[i]]*(1-k[i]);
            double x2 = dp[i-1][j-1][1]+dist[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dist[c[i-1]][d[i]]*(1-k[i-1])*k[i];
           x2 +=dist[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dist[d[i-1]][d[i]]*k[i-1]*k[i];
            dp[i][j][1] = min(x1,x2);
            
      }
    }
      
}


int main(){
    memset(dist,0x3f,sizeof(dist));
    n = read(),m = read(),v = read(),e = read();
    for(int i = 1; i <= n; i++)c[i] = read();
    for(int i = 1; i <= n; i++)d[i] = read();
    for(int i = 1; i <= n; i++)scanf("%lf",&k[i]);
    for(int a = 1; a <= e; a++){
        int u = read(),vv = read(),d = read();
        if(u == vv)continue;
        if(dist[u][vv] < d)continue;
        dist[u][vv] = dist[vv][u] = d;
    }
    floyd();
    DP();
    double ans = 1e30;
    for(int i = 0; i <= m; i++)ans = min(ans,min(dp[n][i][0],dp[n][i][1]));
    printf("%.2f\n",ans);
    return 0;
} 

NOIP2016 DAY1 T3 換教室