1. 程式人生 > >[NOIP2016]換教室

[NOIP2016]換教室

傳送門

f[i][j][k]f[i][j][k]ii表示走完前ii個教室,jj表示換了jj次,kk表示當前教室有沒有換。

d[i]d[i]為兩個教室之間的最短距離。

轉移中的幾種情況應該都比較好理解…(懶…)

#include<bits/stdc++.h>
#define min(a,b) ((a)<(b))?(a):(b)
using namespace std;
const double inf=1e17+5;
int n,m,v,e,c[2005][2],d[305][305];
double k[2005],f[2005][2005][2],ans=inf;
int main(){
	memset(d,63,sizeof(d));
	scanf("%d%d%d%d",&n,&m,&v,&e);
	for(int i=1;i<=n;++i) scanf("%d",&c[i][0]);
	for(int i=1;i<=n;++i) scanf("%d",&c[i][1]);
	for(int i=1;i<=n;++i) scanf("%lf",&k[i]);
	for(int i=1,x,y,z;i<=e;++i){
		scanf("%d%d%d",&x,&y,&z);
		d[x][y]=d[y][x]=min(d[x][y],z);
	}
    for(int i=1;i<=v;++i) d[i][i]=d[i][0]=d[0][i]=0;
    for(int l=1;l<=v;++l)
    for(int i=1;i<=v;++i)
    for(int j=1;j<=v;++j)
    d[i][j]=min(d[i][j],d[i][l]+d[l][j]);
    for(int i=0;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=2;i<=n;++i){
    	f[i][0][0]=f[i-1][0][0]+d[c[i-1][0]][c[i][0]];
    	for(int j=1,mm=min(i,m);j<=mm;++j){
    		int x=c[i-1][0],y=c[i-1][1],z=c[i][0],w=c[i][1];
    		f[i][j][0]=min(f[i][j][0],min(f[i-1][j][0]+d[x][z],f[i-1][j][1]+d[x][z]*(1-k[i-1])+d[y][z]*k[i-1]));
    		f[i][j][1]=min(f[i][j][1],min(f[i-1][j-1][0]+d[x][z]*(1-k[i])+d[x][w]*k[i],f[i-1][j-1][1]+d[y][w]*k[i]*k[i-1]+d[y][z]*k[i-1]*(1-k[i])+d[x][w]*(1-k[i-1])*k[i]+d[x][z]*(1-k[i-1])*(1-k[i])));
		}
	}for(int i=0;i<=m;++i) ans=min(ans,min(f[n][i][0],f[n][i][1]));
	return !printf("%.2lf",ans);
}