【NOIP2016】换教室

题面

 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程。  在可以选择的课程中,有2n节课程安排在n个时间段上。在第 i ( 1≤ i≤n)个时间段上, 两节内容相同的课程同时在不同的地点进行, 其中, 牛牛预先被安排在教室 ci上课, 而另一节课程在教室 di进行。  在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的n节安排好的课程。如果学生想更换第i节课程的教室,则需要提出中情。若申请通过,学生就可以在第 i个时间段去教室 di上课, 否则仍然在教室 ci上课。  由于更换教室的需求太多, 申请不一定能获得通过。 通过计算, 牛牛发现申请更换第 i节课程的教室时, 中情被通过的概率是一个已知的实数 ki, 并且对于不同课程的申请, 被通过的概率是互相独立的。  学校规定, 所有的申请只能在学期开始前一次性提交, 并且每个人只能选择至多m节课程进行申请。 这意味着牛牛必须一次性决定是否申请更换每节课的教室, 而不能根据某些课程的申请结果来决定其他课程是否申请; 牛牛可以申请白己最希望更换教室的 m门课程,也可以不用完这m个中情的机会,甚至可以一门课程都不申请。  因为不同的课程可能会被安排在不同的教室进行, 所以牛牛需要利用课问时间从一间教室赶到另一间教室。  牛牛所在的大学有 v个教室,有 e条道路。每条道路连接两间教室, 并且是可以双向通行的。 由于道路的长度和拥;i者程度不同, 通过不同的道路耗费的体力可能会有所不同。当第i ( 1≤i≤n-1 )节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。  现在牛牛想知道,申请哪几门课程可以使他因在教室问移动耗费的体力值的总和的期望值最小,请你帮他求出这个最小值。  

  数据范围   1<=n<=2000  1<=m<=2000  1<=v<=300

分析

很ju而且长得还很可爱还很温柔的学妹zyw昨天下午讲了一下,那是初见此题,没想到思路这么裸,比前年那个t2简单吧..qvq
首先预处理两点间的最短距离,教室只有300间,Floyd最合适
状态定义
f[i][j][0/1]表示对于到第i个课程为止,用了j个申请机会,并且当前第i个课程是(1)否(0)申请
转移方程
1.不申请当前课程
f[i][j][0]=min(f[i-1][j][1]+e[d[i-1]][c[i]]*p[i-1]+e[c[i-1]][c[i]]*(1-p[i-1]),f[i-1][j][0]+e[c[i-1]][c[i]])
那前一门课程可能申请了,也可能没申请,分别转移过来。
2.申请当前课程
如果前一门也申请了,那就有四种情况。
①都通过
②都没通过
③前一门通过
④后一门通过
没申请的话就两种情况
①后一门通过
②后一门没通过
f[i][j][1]=min{
f[i-1][j-1][1]+e[d[i-1]][d[i]]*p[i-1]*p[i]+e[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+e[c[i-1]][d[i]]*(1-p[i-1])*p[i]+e[d[i-1]][c[i]]*p[i-1]*(1-p[i]),
f[i-1][j-1][0]+e[c[i-1]][d[i]]*p[i]+e[c[i-1]][c[i]]*(1-p[i]) }

被自己菜哭了,方程20min解决,前前后后居然调了3h,检查dp方程检查到眼睛疼,结果是Floyd写挂了..

代码

#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define M 310
#define INF 999999999
int n,m,v,s;
int c[N],d[N],e[M][M];
double ans=INF,p[N],f[N][N][2];
int main()
{
    scanf("%d%d%d%d",&n,&m,&v,&s);
    for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    for(int i=1;i<=n;i++)scanf("%d",&d[i]);
    for(int i=1;i<=n;i++)scanf("%lf",&p[i]);
    for(int i=1;i<=v;i++)
        for(int j=1;j<i;j++)
            e[i][j]=e[j][i]=INF;
    for(int i=1;i<=s;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        e[u][v]=e[v][u]=w<e[v][u]?w:e[v][u];
    }    
    for(int k=1;k<=v;k++)
        for(int i=1;i<=v;i++)
            for(int j=1;j<i;j++)
                if(e[i][k]+e[k][j]<e[i][j])
                    e[i][j]=e[j][i]=e[i][k]+e[k][j];
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            f[i][j][1]=f[i][j][0]=INF;
    f[1][0][0]=f[1][1][1]=0;
    for(int i=2;i<=n;i++)
        for(int j=0;j<=(m<i?m:i);j++)
        {
            f[i][j][0]=min(f[i-1][j][1]+e[d[i-1]][c[i]]*p[i-1]+e[c[i-1]][c[i]]*(1-p[i-1]),f[i-1][j][0]+e[c[i-1]][c[i]]);
            if(j!=0)
                f[i][j][1]=min(f[i-1][j-1][1]+e[d[i-1]][d[i]]*p[i-1]*p[i]+e[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+e[c[i-1]][d[i]]*(1-p[i-1])*p[i]+e[d[i-1]][c[i]]*p[i-1]*(1-p[i]), f[i-1][j-1][0]+e[c[i-1]][d[i]]*p[i]+e[c[i-1]][c[i]]*(1-p[i])); 
        }
    for(int i=0;i<=m;i++)
        ans=min(ans,min(f[n][i][0],f[n][i][1]));
    printf("%.2lf",ans);
    return 0;
        
}

 

posted @ 2018-10-02 11:51  WJEMail  阅读(157)  评论(0编辑  收藏  举报