[NOIP2016]换教室 BZOJ 4720
这道题应该是一个概率dp
首先先用floyd跑一遍处理处最短路,其中两点需要注意
1、dis[i][i]要初始化为零
2、注意有重边!!!!
之后就开始dp转移,用f[i][j][k] 来表示状态,i 表示是i 时刻;j表示还剩下多少可以换教室的机会;当k=0表示在i时间点,剩下j的机会的情况下,不换教室,k=1表示换教室;
所以f[i][j][0]=min(f[i-1][j][0]+dis[beg[i-1]][beg[i]],f[i-1][j][1]+dis[beg[i-1]][beg[i]]*(1-p[i-1])+dis[ano[i-1]][beg[i]]*p[i]),其中p[i]是i时刻换教室的成功概率,beg[i]是初始教室,ano[i]是可换的教室;
f[i][j-1][0]=min(f[i-1][j][0]+(
double
)dis[beg[i-1]][beg[i]]*(1-p[i])+(
double
)dis[beg[i-1]][ano[i]]*p[i],
f[i-1][j][1]+(
double
)dis[beg[i-1]][beg[i]]*(1-p[i-1])*(1-p[i])+(
double
)dis[beg[i-1]][ano[i]]
*(1-p[i-1])*p[i]
+(
double
)dis[ano[i-1]][beg[i]]*p[i-1]*(1-p[i])
+(
double
)dis[ano[i-1]][ano[i]]*p[i-1]*p[i]
)转移方程有点长的,但总之就是在四个可行的道路之间选择,并乘上概率,就这么一直转移到n即可,在for循环找一遍答案就行了
1 #include<cmath> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 int n,m,dian_shu,bian_shu; 9 int beg[2010],ano[2010]; 10 double p[2010]; 11 int dis[310][310]; 12 double f[2010][2010][3]; 13 void ot(){ 14 for(int i=1;i<=n;i++){ 15 for(int j=0;j<=m;j++){ 16 cout<<"ij= "<<i<<" "<<j<<endl; 17 cout<<f[i][j][0]<<" "<<f[i][j][1]<<endl; 18 } 19 } 20 } 21 void ot2(){ 22 for(int i=0;i<=m;i++){ 23 cout<<"i== "<<i<<endl; 24 cout<<"-- "<<f[2][i][0]<<" "<<f[2][i][1]<<endl; 25 } 26 } 27 void init(){ 28 for(int i=1;i<=n;i++) scanf("%d",&beg[i]); 29 for(int i=1;i<=n;i++) scanf("%d",&ano[i]); 30 for(int i=1;i<=n;i++) scanf("%lf",&p[i]); 31 int x,y,z; 32 memset(dis,30,sizeof(dis)); 33 for(int i=1;i<=dian_shu;i++) 34 dis[i][i]=0; 35 for(int i=1;i<=bian_shu;i++){ 36 scanf("%d%d%d",&x,&y,&z); 37 dis[x][y]=min(dis[x][y],z); dis[y][x]=min(dis[y][x],z); 38 } 39 for(int k=1;k<=dian_shu;k++){ 40 for(int i=1;i<=dian_shu;i++){ 41 for(int j=1;j<=dian_shu;j++){ 42 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); 43 } 44 } 45 } 46 } 47 void Dp(){ 48 for(int i=1;i<=n;i++){ 49 for(int j=0;j<=m;j++){ 50 f[i][j][1]=f[i][j][0]=200000000.0; 51 } 52 } 53 f[1][m][0]=0; 54 f[1][m-1][1]=0; 55 for(int i=2;i<=n;i++){ 56 for(int j=m;j>=0;j--){ 57 f[i][j][0]=min( f[i-1][j][0] + (double)dis[beg[i-1]][beg[i]] ,f[i-1][j][1] + (double)(1-p[i-1])*dis[beg[i-1]][beg[i]] + (double)p[i-1]*dis[ano[i-1]][beg[i]]); 58 if(j==0) continue; 59 double aa=f[i-1][j][0]+(double)dis[beg[i-1]][beg[i]]*(1-p[i])+(double)dis[beg[i-1]][ano[i]]*p[i]; 60 double bb=f[i-1][j][1]+(double)dis[beg[i-1]][beg[i]]*(1-p[i-1])*(1-p[i])+(double)dis[beg[i-1]][ano[i]]*(1-p[i-1])*p[i] 61 +(double)dis[ano[i-1]][beg[i]]*p[i-1]*(1-p[i])+(double)dis[ano[i-1]][ano[i]]*p[i-1]*p[i]; 62 /*if(i==2 && j==1){ 63 cout<<(double)dis[ano[i-1]][ano[i]]*p[i-1]*p[i]<<endl; 64 cout<<"--> "<<aa<<" "<<bb<<endl; 65 }*/ 66 f[i][j-1][1]=min(aa,bb); 67 } 68 } 69 } 70 int main(){ 71 //freopen("classrooma.in","r",stdin); 72 //freopen("classrooma.out","w",stdout); 73 scanf("%d%d%d%d",&n,&m,&dian_shu,&bian_shu); 74 init(); 75 Dp(); 76 double ans=200000000.0; 77 for(int i=0;i<=m;i++){ 78 ans=min(ans,f[n][i][0]); 79 ans=min(ans,f[n][i][1]); 80 } 81 //ot(); 82 // ot2(); 83 /* 84 int sc=0; 85 cout<<"st"<<endl; 86 for(int i=2;i<=n;i++){ 87 sc+=dis[beg[i-1]][beg[i]]; 88 cout<<dis[beg[i-1]][beg[i]]<<endl; 89 } 90 cout<<"sc== "<<sc<<endl;*/ 91 printf("%.2lf",ans); 92 return 0; 93 94 } 95 /**********************************************