换教室
Time Limit: 20 Sec Memory Limit: 512 MB
Description
第一行四个整数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;
保证通过学校里的道路,从任何一间教室出发,都能到达其他所有的教室。
保证输入的实数最多包含3位小数。
Output
输出一行,包含一个实数,四舎五入精确到小数点后恰好2位,表示答案。你的
输出必须和标准输出完全一样才算正确。
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
HINT
1≤aj,bj≤v, 1≤wj≤100。
1≤n≤2000, 0≤m≤2000, 1≤v≤300, 0≤e≤90000。
Main idea
给定n个 原本教室ci 和 替换教室di,可以申请m次换课,如果 i 换课了则可以在di上课,否则在ci上课,每个教室之间有距离,求期望最小距离。
Solution
很简单的期望DP,我们令 f[i][j][0\1] 表示 到了第 i 个状态,已经换了 j 次课,这次换不换课,然后分四种情况讨论一下即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| #include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> using namespace std;
#define Road(a,b) (double)w[a][b] #define tense(a,b) a = a<b ? a:b;
const int ONE = 2005; const double INF = 1e18;
int n,m,v,e; int x,y,z; int c[ONE],d[ONE]; int w[301][301]; double f[ONE][ONE][2],k[ONE]; double Ans;
int get() { int res=1,Q=1;char c; while( (c=getchar())<48 || c>57 ) if(c=='-')Q=-1; res=c-48; while( (c=getchar())>=48 && c<=57 ) res=res*10+c-48; return res*Q; }
void Floyed() { for(int k=1; k<=v; k++) for(int i=1; i<=v; i++) for(int j=1; j<=v; j++) tense(w[i][j], w[i][k] + w[k][j]); }
double Eap10(int i) { return Road( c[i],c[i+1] ) * (1-k[i]) + Road( d[i],c[i+1] ) * k[i]; }
double Eap01(int i) { return Road( c[i],c[i+1] ) * (1-k[i+1]) + Road( c[i],d[i+1] ) * k[i+1]; }
double Eap11(int i) { return Road( c[i], c[i+1] ) * (1-k[i]) * (1-k[i+1]) + Road( c[i], d[i+1] ) * (1-k[i]) * k[i+1] + Road( d[i], c[i+1] ) * k[i] * (1-k[i+1]) + Road( d[i], d[i+1] ) * k[i] * k[i+1]; }
void DisApply(int i,int j) { if(j>=0) f[i+1][j][0] = tense(f[i+1][j][0], f[i][j][0] + Road( c[i],c[i+1] ) ); if(j>=1) f[i+1][j][0] = tense(f[i+1][j][0], f[i][j][1] + Eap10(i) ); }
void Apply(int i,int j) { if(j>=1) f[i+1][j][1] = tense(f[i+1][j][1], f[i][j-1][0] + Eap01(i) ); if(j>=2) f[i+1][j][1] = tense(f[i+1][j][1], f[i][j-1][1] + Eap11(i) ); }
int main() { n = get(); m = get(); v = get(); e = get(); for(int i=1; i<=n; i++) c[i] = get(); for(int i=1; i<=n; i++) d[i] = get(); for(int i=1; i<=n; i++) scanf("%lf", &k[i]);
memset(w, 1, sizeof(w)); for(int i=1; i<=v; i++) w[i][i] = 0; for(int i=1; i<=e; i++) { x = get(); y = get(); z = get(); w[x][y] = min(w[x][y], z); w[y][x] = min(w[y][x], z); } Floyed();
for(int i=1; i<=n; i++) for(int j=0; j<=m; j++) f[i][j][0] = f[i][j][1] = INF; f[1][0][0] = f[1][1][1] = 0;
for(int i=1; i<=n-1; i++) for(int j=0; j<=m; j++) DisApply(i,j), Apply(i,j);
Ans = INF; for(int j=0; j<=m; j++) { tense(Ans, f[n][j][0]); tense(Ans, f[n][j][1]); }
printf("%.2lf",Ans); }
|