1. 程式人生 > >【NOIP2016TG D1T3】換教室解題報告

【NOIP2016TG D1T3】換教室解題報告

本來幾個月前就想做這道題就學了期望,結果那天死活調不出來之後就忘了這件事了……然後rty dalao今天想起做這道題來了我想起來這事就又把這個題拿了出來調了一上午調出來了,誰知道錯竟然在預處理上……

【這件事告訴我們一個道理,就是你的程式可能本來沒錯,就因為預處理就崩掉了,以後預處理的時候要用點心思= =】

這道題顯而易見就是一道最短路+期望DP,要求最多換m次使路程期望值最小

那麼期望是什麼?
OI中的期望很好理解,就是各結果權值乘上走向該結果的概率之和,對於這道題就是上完n次課後,對於每次上完課後,各可能性“行走的路程 × 走這段路程的概率”之和的總和(好繞口啊= =)
設a[i]表示第i次課本來所在的教室,b[i]表示第i次課可換的教室,c[i]表示第i次課換教室成功的概率,d[x][y]表示從x教室到y教室的距離,換成程式碼來理解,那就能得出(其中j表示已經換過j次教室,j<=m):

本次不換教室:f[i][j][0]=min(f[i-1][j][0]+d[a[i-1]][a[i]],f[i-1][j][1]+d[a[i-1]][a[i]]*(1.0-c[i])+d[b[i-1]][a[i]]*c[i]);
本次要換教室:f[i][j][1]=min(f[i-1][j-1][0]+d[a[i-1]][a[i]]*(1.0-c[i])+d[a[i-1]][b[i]]*c[i],f[i-1][j-1][1]+(1.0-c[i-1])*(1.0-c[i])*d[a[i-1]][a[i]]+(1.0-c[i-1])*c[i]*d[a[i-1]][b[i]]+c[i-1]*(1.0-c[i])*d[b[i-1
]][a[i]]+c[i-1]*c[i]*d[b[i-1]][b[i]]);

可以看到這遞推式非常非常非常非常非常非常非常的——長= =
所以我程式碼裡都是分了一行又一行顯得正常了一些(並沒有)

當然一上來必須先寫個floyd求各教室間最短路,注意這道題喪心病狂的有重邊
(以及不要像博主一樣犯蠢初始化成0x7f7f7f7f = =)
寫完dp以後,就再找一下最小值就好了,記得保留2位小數

例行放醜翻的程式碼(話說這份程式碼跑的蜜汁快……):

#include<cstdio>
const int N=2002;
using namespace std;
double f[N][N][2
]; double c[N],rlt; int a[N],b[N]; int d[303][303]; int n,m,v,e; int getnum(){int num=0;char c=getchar(); while(c<'0')c=getchar(); while(c>='0')num=(num<<3)+(num<<1)+c-'0',c=getchar();return num; } inline double min(const double &a,const double &b){if(a<b)return a;return b;} inline double max(const double &a,const double &b){if(a<b)return a;return b;} int main(){register int i,j,k,l; n=getnum(),m=getnum(),v=getnum(),e=getnum(); for(i=0;i<=v;d[i][i]=0,++i)for(j=0;j<=v;++j)d[i][j]=0x3f3f3f3f; for(i=0;i<=n;++i)for(j=0;j<=m;++j)f[i][j][0]=f[i][j][1]=0x3f3f3f3f; for(i=1;i<=n;++i)a[i]=getnum(); for(i=1;i<=n;++i)b[i]=getnum(); for(i=1;i<=n;++i)scanf("%lf",&c[i]); for(i=1;i<=e;++i){ j=getnum(),k=getnum(),l=getnum(); d[j][k]=d[k][j]=min(d[j][k],l); } for(k=1;k<=v;++k) for(i=1;i<=v;++i) for(j=1;j<=v;++j) if(d[i][j]>d[i][k]+d[k][j]) d[i][j]=d[j][i]=d[i][k]+d[k][j]; f[1][0][0]=f[1][1][1]=0; for(i=2;i<=n;++i){ f[i][0][0]=f[i-1][0][0]+d[a[i-1]][a[i]];k=min(i,m); for(j=1;j<=k;++j){ f[i][j][0]=min(f[i-1][j][0]+d[a[i-1]][a[i]],f[i-1][j][1]+(1.0-c[i-1])*d[a[i-1]][a[i]]+c[i-1]*d[b[i-1]][a[i]]); f[i][j][1]=min(f[i-1][j-1][0]+d[a[i-1]][a[i]]*(1.0-c[i])+d[a[i-1]][b[i]]*c[i] ,f[i-1][j-1][1] +(1.0-c[i-1])*(1.0-c[i])*d[a[i-1]][a[i]] +(1.0-c[i-1])*c[i]*d[a[i-1]][b[i]] +c[i-1]*(1.0-c[i])*d[b[i-1]][a[i]] +c[i-1]*c[i]*d[b[i-1]][b[i]]); } }rlt=f[n][0][0]; for(i=1;i<=m;++i)rlt=min(rlt,min(f[n][i][0],f[n][i][1])); printf("%.2lf",rlt); }