• 「NOIP2016」换教室


    传送门

    Description

    对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。

    在可以选择的课程中,有 $ 2n $ 节课程安排在 $ n $ 个时间段上。在第 $ i $个时间段上 $ (1 leq i leq n) $,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 $ c_i $ 上课,而另一节课程在教室 $ d_i $ 进行。
    在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 $ n $ 节安排好的课程。如果学生想更换第i节课程的教室,则需要提出申请。若申请通过,学生就可以在第 $ i $ 个时间段去教室 $ d_i $ 上课,否则仍然在教室 $ c_i $ 上课。
    由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛发现申请更换第 $ i $ 节课程的教室时,申请被通过的概率是一个已知的实数 $ k_i $,并且对于不同课程的申请,被通过的概率是互相独立的。
    学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多 $ m $ 节课程进行申请。这意味着牛牛必须一次性决定是否申请更换每节课的教室,而不能根据某些课程的申请结果来决定其他课程是否申请;牛牛可以申请自己最希望更换教室的 $ m $ 门课程,也可以不用完这 $ m $ 个申请的机会,甚至可以一门课程都不申请。

    因为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课问时间从一间教室赶到另一间教室。
    牛牛所在的大学有 $ v $ 个教室,有 $ e $ 条道路。每条道路连接两间教室,并且是可以双向通行的。由于道路的长度和拥堵程度不同,通过不同的道路耗费的体力可能会有所不同。当第 $ i (() 1 leq i leq n - 1 $)节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。

    现在牛牛想知道,申请哪几门课程可以使他因在教室间移动耗费的体力值的总和的期望值最小,请你帮他求出这个最小值。

    Solution

    (floyed)算出每个教室之间的最短路

    (f_{i,j,0/1})表示前(i)个教室,申请了(j)个,第(i)间教室有无申请的期望值

    考虑第(i-1)个教室是否有选进行转移即可


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    using namespace std;
    #define reg register
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MN=2005,MV=305;
    const db inf=1e30;
    db p[MN],f[MN][MN][2];
    int d[MN][MN];
    int N,M,V,E,C[MN],D[MN];
    #define rw(x,y) x=min(x,y)
    int main()
    {
    	memset(d,0x3f,sizeof d);
    	N=read(),M=read(),V=read(),E=read();
    	reg int i,j,k,x,y,z;
    	for(i=1;i<=N;++i)C[i]=read();
    	for(i=1;i<=N;++i)D[i]=read();
    	for(i=1;i<=N;++i)scanf("%lf",&p[i]);
    	for(i=1;i<=E;++i)
    		x=read(),y=read(),z=read(),
    		rw(d[x][y],z),rw(d[y][x],z);
    
    	for(k=1;k<=V;++k)for(i=1;i<=V;++i)for(j=1;j<=V;++j)
    		rw(d[i][j],d[i][k]+d[k][j]);
    	for(i=1;i<=V;++i)d[i][0]=d[0][i]=d[i][i]=0;
    	for(i=1;i<=N;++i)for(j=0;j<=M;++j)f[i][j][0]=f[i][j][1]=inf;
    	for(i=1;i<=N;++i)for(j=0;j<=M&&j<=i;++j)
    	{
    		if(i-2>=j)rw(f[i][j][0],f[i-1][j][0]+d[C[i-1]][C[i]]);
    		if(i-1>=j)rw(f[i][j][0],f[i-1][j][1]+d[C[i-1]][C[i]]*(1-p[i-1])+d[D[i-1]][C[i]]*p[i-1]);
    		if(i-1>=j&&j>0)rw(f[i][j][1],f[i-1][j-1][0]+d[C[i-1]][D[i]]*p[i]+d[C[i-1]][C[i]]*(1-p[i]));
    		if(j>0)rw(f[i][j][1],f[i-1][j-1][1]+d[C[i-1]][C[i]]*(1-p[i-1])*(1-p[i])+
    		d[C[i-1]][D[i]]*(1-p[i-1])*p[i]+d[D[i-1]][C[i]]*p[i-1]*(1-p[i])+d[D[i-1]][D[i]]*p[i-1]*p[i]);
    	}
    	db ans=inf;
    	for(i=0;i<=M;++i)rw(ans,f[N][i][0]),rw(ans,f[N][i][1]);
    	printf("%.2lf
    ",ans);
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    第01组 Alpha冲刺(5/6)
    第01组 Alpha冲刺(4/6)
    第01组 Alpha冲刺(3/6)
    第01组 Alpha冲刺(2/6)
    第01组 Alpha冲刺(1/6)
    第01组(17)需求分析报告
    第01组(17)团队展示
    结对编程作业
    Leetcode 每日一题:1014. 最佳观光组合
    Leetcode13. 罗马数字转整数
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/11625809.html
Copyright © 2020-2023  润新知