[NOIP2016]换教室


换教室

这种有某个不定值求最佳情况感觉还是动态规划,但最重要的是找好迭代关系(公式太长,看代码吧)

然后就是求两个点之间耗费体力最少的路的耗费值,数据大小是300,可以使用floyed

//https://ac.nowcoder.com/acm/problem/16428
#include
#define LOCAL
using namespace std;
const int maxn=2010;
const int INF=9e6+10;// 两个点之间耗费体力值之和的最小值
int c[maxn],d[maxn];
double k[maxn];
double dp[maxn][maxn][2];
int mm[305][305];
void floyed(int v){
    for (int k=1;k<=v;++k){
        for (int i=1;i<=v;++i){
            for (int j=i+1;j<=v;++j){
                mm[i][j]=min(mm[i][j],mm[i][k]+mm[k][j]);
                mm[j][i]=mm[i][j];
            }
            // for (int j=1;j<=v;++j){
            //     mm[i][j]=min(mm[i][j],mm[i][k]+mm[k][j]);
            // }
        }
    }
}

int main(){
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif
    std::ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int n,m,v,e;
    cin>>n>>m>>v>>e;
    for (int i=1;i<=n;++i) cin>>c[i];
    for (int i=1;i<=n;++i) cin>>d[i];
    for (int i=1;i<=n;++i) cin>>k[i];
    for (int i=1;i<=v;++i) mm[i][i]=0;
    for (int i=1;i<=v;++i) for (int j=i+1;j<=v;++j) {
        mm[i][j]=INF;
        mm[j][i]=INF;
    }
    for (int i=1;i<=e;++i){
        int a,b,w;
        cin>>a>>b>>w;
        mm[a][b]=min(mm[a][b],w);
        mm[b][a]=mm[a][b];
    }
    floyed(v);
    for (int i=1;i<=n;++i) for (int j=0;j<=m;++j) dp[i][j][0]=dp[i][j][1]=INF;
    // 下面这句错了! 首先dp[1][0][1]是非法的,但它在后面会被用到,所以他要被置为INF
    // 然后从本质上讲,只有dp[1][0][0],dp[1][1][0/1]以及上面那个非法的会被用到,所以其余三个为零
    // for (int i=0;i<=m;++i) dp[1][i][0]=dp[1][i][1]=0;
    dp[1][0][0]=0;dp[1][1][1]=0;dp[1][1][0]=0;
    for (int i=2;i<=n;++i){
        for (int j=0;j<=m;++j){
            dp[i][j][0]=min(dp[i-1][j][0]+mm[c[i-1]][c[i]],dp[i-1][j][1]+mm[d[i-1]][c[i]]*k[i-1]+mm[c[i-1]][c[i]]*(1-k[i-1]));
            if (j) dp[i][j][1]=min(dp[i-1][j-1][0]+mm[c[i-1]][d[i]]*k[i]+mm[c[i-1]][c[i]]*(1-k[i]),dp[i-1][j-1][1]+mm[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+mm[c[i-1]][d[i]]*(1-k[i-1])*k[i]+mm[d[i-1]][c[i]]*k[i-1]*(1-k[i])+mm[d[i-1]][d[i]]*k[i-1]*k[i]);
        }
    }
    // double ans=min(dp[n][m][0],dp[n][m][1]);
    double ans=INF;
    for (int i=0;i<=m;++i) {
        double tmpans=min(dp[n][i][0],dp[n][i][1]);
        ans=min(ans,tmpans);
    }
    printf("%.2lf",ans);
    return 0;
}