当前位置 博文首页 > 文章内容

    换教室 P1850 (NOIP 2016)

    作者: 栏目:未分类 时间:2020-09-09 18:01:15

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    P1850

    首先,我们从一节课的教室到另一节课的教室的距离显然需要尽可能小,所以可以预先跑一遍 Floyed ,把距离处理出来

    其次,对于这道 DP ,我们设

    \(f[i][j][0/1]\) 为当前已经处理到第 \(i\) 节课,算上本堂课一共用了 \(j\) 次换教室的机会所产生的最小期望和, 其中 \(0/1\) 表示这一节课是换教室,还是不换教室

    那么预处理的时候,显然,我们需要将 \(f[1][1][1]\) 以及 \(f[1][0][0]\) 均赋值为 \(0\) ,因为第一节课不管换不换教室,到教室的距离总是为 \(0\)


    接下来,我们考虑这些状态之间怎么转移

    先看代码:

    	for(int i=2;i<=n;i++)
    	{
    		double len1=dis[t1[i-1]][t1[i]];//上一节和这一节都不换教室
    		double len2=dis[t1[i-1]][t2[i]];//上一节不换教室,这一节换教室
    		double len3=dis[t2[i-1]][t1[i]];//上一节换教室,这一节不换教室
    		double len4=dis[t2[i-1]][t2[i]];//上一节和这一节都换教室
    		
    		for(int j=0;j<=min(m,i);j++)
    		{
    			f[i][j][0]=min(f[i-1][j][0]+len1,f[i-1][j][1]+len3*p[i-1]+len1*(1-p[i-1]));
    			if(j!=0) f[i][j][1]=min(f[i-1][j-1][0]+len2*p[i]+len1*(1-p[i]),f[i-1][j-1][1]+len1*(1-p[i-1])*(1-p[i])+len2*(1-p[i-1])*p[i]+len3*p[i-1]*(1-p[i])+len4*p[i-1]*p[i]);
    		}
    	}
    

    \(len_i\) 表示教室与教室之间的距离 )

    对于第一个 \(f[i][j][0]\) 的转移方程中,由期望公式可以得到 \(len3*p[i-1]+len1*(1-p[i-1])\) ,其中 \(1-p[i-1]\) 为不会发生的概率

    对于第二个 \(f[i][j][1]\) 的转移方程中,min 函数左侧的式子可以参考上面 \(f[i][j][0]\) 的式子,min 函数右侧的式子即为在上一次与这一次都提出换教室申请时所有可能出现的情况的枚举讨论


    完整代码:

    #include<iostream>
    #include<math.h>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #define ll long long
    using namespace std;
    
    const ll maxn=2e3+10;
    
    int n,m,v,e;
    int t1[maxn],t2[maxn],head[maxn],tot;
    double dis[maxn][maxn];
    double p[maxn];
    double f[maxn][maxn][2];
    
    inline double _min(double a,double b)
    {
    	return a < b ? a : b;
    }
    
    int main(void)
    {
    	scanf("%d%d%d%d",&n,&m,&v,&e);
    	
    	for(int i=1;i<=v;i++)
    	{
    		for(int j=1;j<i;j++)
    		{
    			dis[i][j]=dis[j][i]=999999999;
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=0;j<=m;j++)
    		{
    			f[i][j][0]=f[i][j][1]=999999999;
    		}
    	}
    	
    	for(int i=1;i<=n;i++) scanf("%d",&t1[i]);
    	for(int i=1;i<=n;i++) scanf("%d",&t2[i]);
    	for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
    	for(int i=1;i<=e;i++)
    	{
    		int u,v;
    		double w;
    		scanf("%d%d%lf",&u,&v,&w);
    		dis[u][v]=dis[v][u]=min(dis[u][v],w);
    	}
    	
    	for(int k=1;k<=v;k++)
    	{
    		for(int i=1;i<=v;i++)
    		{
    			for(int j=1;j<i;j++)
    			{
    				dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][k]+dis[k][j]);
    			}
    		}
    	}
    	
    	f[1][1][1]=f[1][0][0]=0;
    	
    	for(int i=2;i<=n;i++)
    	{
    		double len1=dis[t1[i-1]][t1[i]];
    		double len2=dis[t1[i-1]][t2[i]];
    		double len3=dis[t2[i-1]][t1[i]];
    		double len4=dis[t2[i-1]][t2[i]];
    		
    		for(int j=0;j<=min(m,i);j++)
    		{
    			f[i][j][0]=min(f[i-1][j][0]+len1,f[i-1][j][1]+len3*p[i-1]+len1*(1-p[i-1]));
    			if(j!=0) f[i][j][1]=min(f[i-1][j-1][0]+len2*p[i]+len1*(1-p[i]),f[i-1][j-1][1]+len1*(1-p[i-1])*(1-p[i])+len2*(1-p[i-1])*p[i]+len3*p[i-1]*(1-p[i])+len4*p[i-1]*p[i]);
    		}
    	}
    	
    	double ans=999999999;
    	
    	for(int i=0;i<=m;i++)
    	{
    		ans=min(f[n][i][0],min(f[n][i][1],ans));
    	}
    	
    	printf("%.2lf\n",ans);
    	
    	return 0;
    }