P1850 [NOIP2016 提高组] 换教室

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1850 [NOIP2016 提高组] 换教室相关的知识,希望对你有一定的参考价值。

P1850 [NOIP2016 提高组] 换教室

题意:

有2n个课安排在n个时间段上,每个时间段上都有两个一样的课同时在不同地方上,起初牛牛被所有课都被安排在Ci上课,另一节课在Di上课。牛牛现在想跟换到Di位置,它最多可以申请m节课换教室,对于每节课换成功的概率为P[i],每个教室之间都有距离,问申请哪几门课程可以使他在教室间的移动总和的期望值最小,输出这个最小值
注意申请教室是一次性的,无法根据其他课的申请结果来决定其他课程是否申请

题解:

按照一般的思路,我们会设dp[i][j]表示前i个课我们申请了j节,移动的最小期望值。dp[i][j] =min(dp[i-1][j-1]+p[i] * dis +dp[i-1][j]+(1-p[i]) * dis),我们可能会得到这样的方程,但是有个大问题,因为我们在转移过程中被认为是知道上一次申请的结果的,但是在题目中,所有申请是一次提交的,我们并不知道上一次申请会是什么样的结果,所以二维状态是不够用的。所以我们设dp[i][j][0/1],前两维意思相同,第三维表示我们假设第i个教室我们没有选择交换(交换是否成功未知,只是我们提交了申请)
那么我们转移会有考虑当前当前是否转移,以及上一次是否转移
转移情况如图:

详细见代码吧

代码:

调了半天不知道哪写错了,直接找了AC代码

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){
   ll s=0,w=1ll;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=2030;
double dp[maxn][maxn][3];
double dis[maxn][maxn];
int c[maxn],d[maxn];
double p[maxn];
int n,m,v,e;
void Floyd(){
	for(int i=1;i<=v;i++){
		for(int j=1;j<=v;j++){
			for(int k=1;k<=v;k++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
}
void init(){
	for(int i=1;i<=v;i++){
		for(int j=1;j<=v;j++){
			dis[i][j]=1e9;
		}
	}
}
int main()
{
	cin>>n>>m>>v>>e;
	init();
	for(int i=1;i<=n;i++)cin>>c[i];
	for(int i=1;i<=n;i++)cin>>d[i];
	for(int i=1;i<=n;i++)cin>>p[i];
	for(int i=1;i<=e;i++){
		int u,v,w;
		cin>>u>>v>>w;
		dis[u][v]=w;
		dis[v][u]=w;
	}
	Floyd();
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			dp[i][j][0]=dp[i][j][1]=1e9;
		}
	}
	dp[1][0][0]=dp[1][1][1]=0; //初始化 
	for(int i=2;i<=n;i++){

		for(int j=0;j<=min(m,i);j++){
			
			dp[i][j][0]=min(dp[i-1][j][0]+dis[c[i-1]][c[i]],
			dp[i-1][j][1]+dis[d[i-1]][c[i]]*p[i-1]
			+dis[c[i-1]][c[i]]*(1-p[i-1]));
			
			if(j!=0)
			dp[i][j][1]=min(
			dp[i-1][j-1][0]
			+dis[c[i-1]][d[i]]*p[i]
			+dis[c[i-1]][c[i]]*(1-p[i]),
			
			dp[i-1][j-1][1]+
			dis[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])
			+dis[c[i-1]][d[i]]*(1-p[i-1])*p[i]
			+dis[d[i-1]][c[i]]*(1-p[i])*p[i-1]
			+dis[d[i-1]][d[i]]*p[i-1]*p[i]);
		}
	}
	double Dis=1e9;
	for(int i=0;i<=m;i++)
		Dis=min(min(dp[n][i][0],dp[n][i][1]),Dis);
	printf("%.2f",Dis);
	return 0;
}


AC代码

#include<iostream>
#include<cstdio>
using namespace std;
double p[10001],f[2001][2001],dp[2001][2001][2];
int a[2001][2001],c[20001],d[20001];
inline double min(double a,double b){
    return a<b?a:b;
}
inline int  qread(){
    int  k = 0;
    char c;
    c = getchar();
    while(!isdigit(c))c = getchar();
 	while(isdigit(c)){
        k = (k<<1)+(k<<3)+c-48;
    	c = getchar();
    }
    return k ;
}
int main()
{
    int n,m,v,e,a1,b1,c1;
    cin>>n>>m>>v>>e;
    for(  int i=1;i<=n;i++)c[i]=qread();
    for(  int i=1;i<=n;i++)d[i]=qread();
    for(  int i=1;i<=n;i++)cin>>p[i];
    
    for(  int i=1;i<=v;i++)
     for(  int j=1;j<i;j++)
      f[i][j]=f[j][i]=999999999;
   
    for(  int i=1;i<=e;i++){
    	a1=qread(),b1=qread(),c1=qread();
        f[a1][b1]=f[b1][a1]=min(f[a1][b1],c1);
    }
    
    for(  int k=1;k<=v;k++)
      for(  int i=1;i<=v;i++)
        for(  int j=1;j<i;j++)
          if(f[i][k]+f[k][j]<f[i][j])
             f[i][j]=f[j][i]=f[i][k]+f[k][j];
             
    for(  int i=1;i<=n;i++)
        for(  int j=0;j<=m;j++)
            dp[i][j][0]=dp[i][j][1]=999999999;
     
    dp[1][0][0]=dp[1][1][1]=0;
    for(  int i=2;i<=n;i++){
     double add1=f[c[i-1]][c[i]];
      for(  int j=0;j<=min(m,i);j++)
       {                     
          dp[i][j][0]=min(dp[i-1][j][0]+add1,dp[i-1][j][1]+f[d[i-1]][c[i]]*p[i-1]+f[c[i-1]][c[i]]*(1-p[i-1]));
          if(j!=0)
          dp[i][j][1]=min(dp[i-1][j-1][0]+f[c[i-1]][d[i]]*p[i]+f[c[i-1]][c[i]]*(1-p[i]),dp[i-1][j-1][1]+f[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+f[c[i-1]][d[i]]*(1-p[i-1])*p[i]+f[d[i-1]][c[i]]*(1-p[i])*p[i-1]+f[d[i-1]][d[i]]*p[i-1]*p[i]);
       }   
    }          
                               
    double hahaha=9999999999;
    for(int i=0;i<=m;i++){
    hahaha=min(dp[n][i][0],min(dp[n][i][1],hahaha));}
    printf("%.2lf",hahaha);
}

以上是关于P1850 [NOIP2016 提高组] 换教室的主要内容,如果未能解决你的问题,请参考以下文章

[NOIP2016提高组]换教室

[NOIp2016提高组]换教室

NOIP2016提高组day1?换教室

NOIP2016提高组换教室

NOIP2016提高组 Day1 T3 换教室

做题记录:P1850 换教室