• 【NOIP2016】换教室 题解


      最后一次参NOIP的时候的day1t3,当时就没能AC出来,没想到过了三年最终还是要因为练习最短路而写这题。

      这就是善恶终有报苍天饶过谁吗。

      题目描述略,总体来说就是个DP(顺便使用最短路预处理),对于期望的运用也是很基础的部分。当年考场上我要是没被期望吓傻应该能够A掉这题吧

      DP[i][j][0]表示第i个时间段,换了j次教室,当前不换教室。DP[i][j][1]表示当前申请换教室。

      那么DP[i][j][0]可以从DP[i-1][j][0]和DP[i-1][j][1]转移而来,DP[i][j][1]可以从DP[i-1][j-1][0]和DP[i-1][j-1][1]中转移而来。

      具体的转移方程式太麻烦不写了,仔细思考就OK,不是很难。

      最开始使用Floyd预先跑个全源最短路预处理,这就是本题的最短路部分吧(悲)

      不卡精度非常良心。

      那么下面是代码。

      

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const double INF=1e10;
    int n,m,v,e;
    int dis[305][305]={0},A[2005]={0},B[2005]={0};
    double pos[2005],DP[2005][2005][3];
    void Floyd();
    void WriteIn();
    int main(void)
    {
        memset(dis,127/2,sizeof(dis));
        WriteIn();
        Floyd();
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)
                DP[i][j][1]=DP[i][j][0]=INF;
        DP[1][0][0]=0;
        DP[1][1][1]=0;
        double tmp;
        for(int i=2;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                DP[i][j][0]=min(DP[i][j][0],DP[i-1][j][0]+dis[A[i-1]][A[i]]);
                DP[i][j][0]=min(DP[i][j][0],DP[i-1][j][1]+dis[A[i-1]][A[i]]*(1.0-pos[i-1])+dis[B[i-1]][A[i]]*pos[i-1]);
                if(!j)continue;
                DP[i][j][1]=min(DP[i][j][1],DP[i-1][j-1][0]+dis[A[i-1]][A[i]]*(1.0-pos[i])+dis[A[i-1]][B[i]]*pos[i]);
                tmp=dis[A[i-1]][A[i]]*(1.0-pos[i])*(1.0-pos[i-1])+dis[A[i-1]][B[i]]*pos[i]*(1-pos[i-1]);
                tmp+=dis[B[i-1]][A[i]]*(1.0-pos[i])*pos[i-1]+dis[B[i-1]][B[i]]*pos[i]*pos[i-1];
                DP[i][j][1]=min(DP[i][j][1],DP[i-1][j-1][1]+tmp);
            }
        }
        double ans=INF;
        for(int i=0;i<=m;i++)
        {
            ans=min(ans,DP[n][i][1]);
            ans=min(ans,DP[n][i][0]);
        }
        printf("%.2f",ans);
        return 0;
    }
    
    void WriteIn()
    {
        scanf("%d%d%d%d",&n,&m,&v,&e);
        int a,b,c;
        for(int i=1;i<=n;i++)scanf("%d",&A[i]);
        for(int i=1;i<=n;i++)scanf("%d",&B[i]);
        for(int i=1;i<=n;i++)scanf("%lf",&pos[i]);
        for(int i=1;i<=v;i++)dis[i][i]=0;
        for(int i=1;i<=e;i++) 
        {
            scanf("%d%d%d",&a,&b,&c);
            dis[a][b]=min(dis[a][b],c);
            dis[b][a]=min(dis[a][b],c);
        }
        return;
    }
    
    void Floyd()
    {
        for(int k=1;k<=v;k++)
            for(int i=1;i<=v;i++)
                for(int j=1;j<=v;j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        return;
    }
  • 相关阅读:
    go学习笔记day01
    go学习笔记day02
    SQLSERVER SQL性能优化
    Javascript面向对象编程(二):构造函数的继承
    Net 下采用GET/POST/SOAP方式动态调用WebService
    Asp.Net下采用GET/POST/SOAP方式动态调用WebService
    crontab用法(例子)
    Javascript面向对象编程(三):非构造函数的继承
    学习Javascript闭包(Closure)
    js 模拟队列类
  • 原文地址:https://www.cnblogs.com/CYWer/p/11732473.html
Copyright © 2020-2023  润新知