我的floyd竟然写错了?今年NOIP怕不是要爆零了?
这就是一个概率dp
我们用$dp[i][j][k]$表示在第$i$个时间段,已经申请了$j$次,$k$表示本次换或不换,然后直接暴力转移
点数只有300,跑一遍floyd
1 //minamoto 2 #include3 #include 4 #include 5 #define inf 1e17 6 using namespace std; 7 template inline bool cmin(T&a,const T&b){ return a>b?a=b,1:0;} 8 inline int read(){ 9 #define num ch-'0'10 char ch;bool flag=0;int res;11 while(!isdigit(ch=getchar()))12 (ch=='-')&&(flag=true);13 for(res=num;isdigit(ch=getchar());res=res*10+num);14 (flag)&&(res=-res);15 #undef num16 return res;17 }18 const int N=2005,M=305;19 int mp[M][M],c[N][2],n,m,e,v;double dp[N][N][2],k[N],ans;20 int main(){21 // freopen("testdata.in","r",stdin);22 memset(mp,0x3f,sizeof(mp));23 n=read(),m=read(),v=read(),e=read();24 for(int i=1;i<=n;++i) c[i][0]=read();25 for(int i=1;i<=n;++i) c[i][1]=read();26 for(int i=1;i<=n;++i) scanf("%lf",&k[i]);27 for(int i=1,u,v,w;i<=e;++i){28 u=read(),v=read(),w=read();29 cmin(mp[u][v],w),cmin(mp[v][u],w);30 }31 for(int i=1;i<=v;++i) mp[i][i]=mp[i][0]=mp[0][i]=0;32 for(int k=1;k<=v;++k) for(int i=1;i<=v;++i) for(int j=1;j<=v;++j)33 cmin(mp[i][j],mp[i][k]+mp[k][j]);34 for(int i=0;i<=n;++i) for(int j=0;j<=m;++j) dp[i][j][0]=dp[i][j][1]=inf;35 dp[1][0][0]=dp[1][1][1]=0;36 for(int i=2;i<=n;++i){37 dp[i][0][0]=dp[i-1][0][0]+mp[c[i][0]][c[i-1][0]];38 for(int j=1,l=min(i,m);j<=l;++j){39 int c1=c[i][0],c2=c[i][1],c3=c[i-1][0],c4=c[i-1][1];40 cmin(dp[i][j][0],dp[i-1][j][0]+mp[c1][c3]);41 cmin(dp[i][j][0],dp[i-1][j][1]+mp[c1][c4]*k[i-1]+mp[c1][c3]*(1-k[i-1]));42 cmin(dp[i][j][1],dp[i-1][j-1][0]+mp[c1][c3]*(1-k[i])+mp[c2][c3]*k[i]);43 cmin(dp[i][j][1],dp[i-1][j-1][1]+mp[c1][c3]*(1-k[i-1])*(1-k[i])+44 mp[c2][c3]*(1-k[i-1])*k[i]+mp[c1][c4]*k[i-1]*(1-k[i])+mp[c2][c4]*k[i-1]*k[i]);45 }46 }47 ans=inf;48 for(int i=0;i<=m;++i) cmin(ans,dp[n][i][0]),cmin(ans,dp[n][i][1]);49 printf("%.2lf\n",ans);50 return 0;51 }