• 换教室 P1850 (NOIP 2016)


    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
    ",ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    PAT Basic 1001
    PAT基础6-11
    PAT基础6-12
    PAT基础6-10
    修改正在进行遍历的列表
    使用管道和cronolog切割日志
    python logging模块
    python实现广度优先搜索和深度优先搜索
    多继承下的super()指向的不一定是直接父类
    python3 pandas DataFrame常见用法
  • 原文地址:https://www.cnblogs.com/jd1412/p/13620657.html
Copyright © 2020-2023  润新知