UOJ262 【NOIP2016】換教室


本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。

 

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!

 

 

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
解題報告:

24分

  注意到有6個測試點m=0,則說明不能提出申請,那么只需要求出全圖的兩兩之間的最短路,路徑唯一確定。

 

52分

  注意到另外有7個測試點m=1,只能提出一次申請。我們可以直接枚舉在哪里提出申請,再與不申請的時候取一個min就可以了。

 

76分

  注意到還有6個測試點m=2,只能提出兩次申請,暴力枚舉哪兩個點申請即可。

 

80分

  其實我們並不需要分那么多類情況討論,考慮直接爆搜,在每個點是否提出申請,最后暴力計算貢獻。因為這樣的復雜度是C(n,m)的,所以m<=2和n<=10是完全沒有問題的,直接可以用搜索拿到80分。

 

100分

  這顯然是一道概率DP裸題。考慮f[i][j][0、1]表示前i堂課,已經申請了j次,這次申不申請的最小期望值,則:

 $${f[i][j][0]=min( f[i-1][j][0]+dis(c[i-1],c[i]),f[i-1][j][1]+dis(c[i-1],c[i])*(1-p[i-1])+dis(d[i-1],c[i])*p[i-1] )}$$

 

 $${f[i][j][1]=min( f[i-1][j-1][0]+dis(c[i-1],d[i])*p[i]+dis(c[i-1],c[i])*(1-p[i]),f[i-1][j-1][1]+dis(c[i-1],c[i])*(1-p[i-1])*(1-p[i])+dis(c[i-1],d[i])*(1-p[i-1])*p[i]+dis(d[i-1],c[i])*p[i-1]*(1-p[i]))+dis(d[i-1],d[i])*p[i-1]*p[i]) }$$

  

 (dis(i,j)表示i到j的最短距離)

 

  需要說明的是,期望是可以線性相加的,也就是說一條路徑上的距離總期望值實際上就等於每兩個相鄰點之間的距離的期望值的總和。另外上面的轉移式可以這樣理解:在我們已經提出申請的情況下,對於所有情況的討論就是在現有的申請情況下的能得到的距離期望值,事實上是根據計算了每條邊的貢獻。

  這樣即可獲得滿分。時間復雜度:O(V3+nm)

 

注意事項

      如果狀態的0、1表示的是地點在c還是d的話會有不少問題,因為壓根就不能體現出申請的時候的成功與失敗結果,但是對於m<=2的點基本不會出錯,大點的出錯概率也不是特別大,就導致這樣完全錯誤的狀態設計在聯賽數據下獲得了88分……

 
 
 1 //It is made by ljh2000
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #include <string>
14 using namespace std;
15 typedef long long LL;
16 const int MAXN = 2011;
17 const int MAXD = 311;
18 const int inf = (1<<29); 
19 int n,m,D,bian,c[MAXN],d[MAXN],dis[MAXD][MAXD];
20 double f[MAXN][MAXN][2],k[MAXN],ans;
21 
22 inline int getint(){
23     int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
24     if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
25 }
26 
27 inline void work(){
28     n=getint(); m=getint(); D=getint(); bian=getint(); int x,y,z,lim; double minl;
29     for(int i=1;i<=n;i++) c[i]=getint(); for(int i=1;i<=n;i++) d[i]=getint(); for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
30     for(int i=1;i<=D;i++) for(int j=1;j<=D;j++) dis[i][j]=inf;
31     for(int i=1;i<=bian;i++) {
32         x=getint(); y=getint(); z=getint();    if(dis[x][y]==inf) dis[x][y]=dis[y][x]=z;
33         else dis[x][y]=min(dis[x][y],z),dis[y][x]=dis[x][y];
34     }
35     for(int l=1;l<=D;l++) for(int i=1;i<=D;i++) if(i!=l) for(int j=1;j<=D;j++) if(j!=l&&i!=j) dis[i][j]=min(dis[i][l]+dis[l][j],dis[i][j]); 
36     for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=1e30; f[1][0][0]=f[1][1][1]=0; 
37     for(int i=1;i<=D;i++) dis[i][i]=0;
38     for(int i=2;i<=n;i++) {
39         lim=min(i,m);
40         for(int j=0;j<=lim;j++) {
41             minl=f[i-1][j][1]+dis[c[i-1]][c[i]]*(1.0-k[i-1])+dis[d[i-1]][c[i]]*k[i-1];
42             minl=min(minl,f[i-1][j][0]+dis[c[i-1]][c[i]]);
43             f[i][j][0]=min(f[i][j][0],minl);
44             if(j>=1) {
45                 minl=f[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1.0-k[i])*(1.0-k[i-1])+dis[c[i-1]][d[i]]*(1.0-k[i-1])*k[i];
46                 minl+=dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[d[i-1]][d[i]]*k[i-1]*k[i];
47                 minl=min(minl,f[i-1][j-1][0]+dis[c[i-1]][d[i]]*k[i]+dis[c[i-1]][c[i]]*(1.0-k[i]));
48                 f[i][j][1]=min(f[i][j][1],minl);
49             }
50         }
51     }
52     ans=1e30; for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
53     printf("%.2lf",ans);
54 }
55 
56 int main()
57 {
58     work();
59     return 0;
60 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM