本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!
Description
Input
Output
Sample Input
2 1 2
1 2 1
0.8 0.2 0.5
1 2 5
1 3 3
2 3 1
Sample Output
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 }