1. 程式人生 > >NOIp2016Day1T3--換教室--概率dp+floyd

NOIp2016Day1T3--換教室--概率dp+floyd

ups mat 連接 學校 wid eset size 現在 依次

題目描述

對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。

在可以選擇的課程中,有 2n 節課程安排在 n 個時間段上。在第i個時間段上,兩節內容相同的課程同時在不同的地點進行,其中,牛牛預先被安排在教室ci上課,而另一節課程在教室 di行。

在不提交任何申請的情況下,學生們需要按時間段的順序依次完成所有的 n 節安排好的課程。如果學生想更換第 i節課程的教室,則需要提出申請。若申請通過,學生就可以在第 i 個時間段去教室 d?i?? 上課,否則仍然在教室 c?i?? 上課。

由於更換教室的需求太多,申請不一定能獲得通過。通過計算,牛牛發現申請更換第 i節課程的教室時,申請被通過的概率是一個已知的實數 k?i??,並且對於不同課程的申請,被通過的概率是互相獨立的。

學校規定,所有的申請只能在學期開始前一次性提交,並且每個人只能選擇至多 m 節課程進行申請。這意味著牛牛必須一次性決定是否申請更換每節課的教室,而不能根據某些課程的申請結果來決定其他課程是否申請;牛牛可以申請自己最希望更換教室的 m 門課程,也可以不用完這 m 個申請的機會,甚至可以一門課程都不申請。

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

牛牛所在的大學有 v 個教室,有 e 條道路。每條道路連接兩間教室,並且是可以雙向通行的。由於道路的長度和擁堵程度不同,通過不同的道路耗費的體力可能會有所不同。 當第 i節課結束後,牛牛就會從這節課的教室出發,選擇一條耗費體力最少的路徑前往下一節課的教室。

現在牛牛想知道,申請哪幾門課程可以使他因在教室間移動耗費的體力值的總和的期望值最小,請你幫他求出這個最小值。

輸入輸出樣例

輸入樣例#1:   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 輸出樣例#1:   2.80 題解:   首先,考慮對於所有的教室與道路,地圖本身是存在最短路的,我們先用floyd求出任意兩點之間的最短距離。   其次,針對所有事件可能發生的情況:     1.當前的課不換的情況:       (1)上一節課也沒換;       (2)上一節課換了----成功or不成功;     2.當前的課換的情況:
      (1)當前課成功換了:         a.上一節課換了----上一節課成功or不成功         b.上一節課沒換;       (2)當前的課換了失敗:         a.上一節課換了----上一節課成功or不成功         b.上一節課沒換;   最後,按步就班地結合題中給出的概率,以及我們用floyd求出的距離,列出轉移方程:   技術分享

  技術分享

技術分享
 1 #include<cmath>
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define yy p[i]*p[i-1]
 7 #define yn p[i-1]*(1.0-p[i])
 8 #define ny (1.0-p[i-1])*p[i]
 9 #define nn (1.0-p[i-1])*(1.0-p[i])
10 using namespace std;
11 
12 const int maxn=2009;
13 double f[maxn][maxn][3];
14 double p[maxn],ans=1.0*1e9;
15 int n,m,v,e;
16 int c[maxn],d[maxn],dis[maxn][maxn];
17 void floyd()
18 {
19     for(int k=1; k<=v; k++)
20     {
21         for(int i=1; i<=v; i++)
22         {
23             for(int j=1; j<=v; j++)
24             {
25                 if(dis[i][j]>dis[i][k]+dis[k][j])
26                 {
27                     dis[i][j]=dis[i][k]+dis[k][j];
28                 }
29             }
30         }
31     }
32 }
33 int main()
34 {
35     cin>>n>>m>>v>>e;
36     for(int i=1; i<=n; i++)
37         cin>>c[i];
38     for(int i=1; i<=n; i++)
39         cin>>d[i];
40     for(int i=1; i<=n; i++)
41         cin>>p[i];
42     for(int i=1; i<=v+10; i++)
43         for(int j=0; j<=v+10; j++)
44             dis[i][j]=1e9;
45     for(int i=0; i<=v; i++)
46         dis[i][i]=0;
47     for(int i=1; i<=e; i++)
48     {
49         int a,b,c;
50         cin>>a>>b>>c;
51         dis[a][b]=dis[b][a]=min(dis[a][b],c);
52     }
53     floyd();
54     for(int i=1; i<=n; i++)
55     {
56         for(int j=0; j<=m; j++)
57         {
58             f[i][j][0]=f[i][j][1]=1.0*1e9;
59         }
60     }
61     f[1][0][0]=f[1][1][1]=0;
62     for(int i=2; i<=n; i++)
63     {
64         for(int j=0; j<=min(m,i); j++)
65         {
66             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.0-p[i-1]) + dis[d[i-1]][c[i]]*p[i-1] );
67             if(j>0)
68             {
69                 f[i][j][1]=min( f[i-1][j-1][0] + dis[c[i-1]][d[i]]*p[i]
70                                 + dis[c[i-1]][c[i]]*(1.0-p[i]),
71 
72                                 f[i-1][j-1][1] + dis[d[i-1]][c[i]]*yn
73                                 + dis[c[i-1]][c[i]]*nn
74                                 + dis[d[i-1]][d[i]]*yy
75                                 + dis[c[i-1]][d[i]]*ny    );
76             }
77         }
78     }
79     for(int i=0; i<=m; i++)
80     {
81         ans=min(ans,min(f[n][i][0],f[n][i][1]));
82     }
83     printf("%.2lf",ans);
84     return 0;
85 }
86 /*
87 3 2 3 3
88 2 1 2
89 1 2 1
90 0.8 0.2 0.5
91 1 2 5
92 1 3 3
93 2 3 1
94 */
View Code

NOIp2016Day1T3--換教室--概率dp+floyd