NOIP2016 DAY1 T3 換教室
阿新 • • 發佈:2017-10-19
pan output clu strong int 情況下 esc 必須 string
第一行四個整數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位小數。
輸出一行,包含一個實數,四舎五入精確到小數點後恰好2位,表示答案。你的
輸出必須和標準輸出完全一樣才算正確。
測試數據保證四舎五入後的答案和準確答案的差的絕對值不大於4*10^-3。(如果你不知道什麽是浮點誤差,這段話
可以理解為:對於大多數的算法,你可以正常地使用浮點數類型而不用對它進行特殊的處理)
2 1 2
1 2 1
0.8 0.2 0.5
1 2 5
1 3 3
2 3 1
我們設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 ;
下面貼代碼,如果有問題 ,請在下面留言。
換教室
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
Output
Sample Input
3 2 3 32 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就行, 不過,這題的動態轉移方程式很.....惡心的。#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 換教室