【uoj262】 NOIP2016—换教室

http://uoj.ac/problem/262 (题目链接)

题意

  有${n}$个时间段,第${i}$个时间段可以选择在${c_i}$教室上课,也可以选择申请换课,有${k_i}$概率申请通过,在${d_i}$上课,另外${1-k_i}$的概率留在${c_i}$教室。 总共有${v}$个教室,${e}$条路径双向联通教室${x_i}$和${y_i}$,路径有权值${w_i}$。在课间时(相邻两个时间段的间隔中),你要从上一个教室走最短路径到下一个教室。 现在你有${m}$次申请机会,只能提前申请一堆换课(也就是你不能在知道某一次申请结果后再去申请下一个换课)。求总距离的最小期望。

Solution

  跟去年那道子串好像啊。。

  先floyd算出图中两两点之间的距离,然后dp。

  用${f[i][j]}$表示上到第${i}$堂课,已经申请了${j}$次,并且第${i}$堂课的教室被申请,所花费的总体力。

  用${g[i][j]}$表示上到第${i}$堂课,已经申请了${j}$次,并且第${i}$堂课的教室没有被申请,所花费的总体力。

  转移很显然$${f[i][j]=Min(f[i-1][j-1]+dis,g[i-1][j-1]+dis)}$$

  $${g[i][j]=Min(f[i-1][j]+dis,g[i-1][j]+dis)}$$

细节

  注意Floyd的总点数是V(好像坑了好多人)。

代码

// uoj262
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define inf 2147483640
#define LL long long
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=2010;
int n,m,E,V;
int c[maxn],d[maxn];
double dis[maxn][maxn],K[maxn],f[maxn][maxn],g[maxn][maxn];

void Floyd() {
	for (int k=1;k<=V;k++)
		for (int i=1;i<=V;i++)
			for (int j=1;j<=V;j++)
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
void dp() {
	for (int i=1;i<=n;i++)
		for (int j=0;j<=m;j++) f[i][j]=g[i][j]=inf;
	g[1][0]=f[1][1]=0;
	for (int i=2;i<=n;i++)
		for (int j=0;j<=min(i,m);j++) {
			if (j) {
				f[i][j]=f[i-1][j-1]+K[i-1]*K[i]*dis[d[i-1]][d[i]];
				f[i][j]+=K[i-1]*(1-K[i])*dis[d[i-1]][c[i]];
				f[i][j]+=(1-K[i-1])*K[i]*dis[c[i-1]][d[i]];
				f[i][j]+=(1-K[i-1])*(1-K[i])*dis[c[i-1]][c[i]];
				f[i][j]=min(f[i][j],g[i-1][j-1]+K[i]*dis[c[i-1]][d[i]]+(1-K[i])*dis[c[i-1]][c[i]]);
			}
			g[i][j]=min(f[i-1][j]+K[i-1]*dis[d[i-1]][c[i]]+(1-K[i-1])*dis[c[i-1]][c[i]],g[i-1][j]+dis[c[i-1]][c[i]]);
		}
}
int main() {
	scanf("%d%d%d%d",&n,&m,&V,&E);
	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",&K[i]);
	for (int i=1;i<=V;i++) {
		for (int j=1;j<=V;j++) dis[i][j]=inf;
		dis[i][i]=0;
	}
	for (int u,v,w,i=1;i<=E;i++) {
		scanf("%d%d%d",&u,&v,&w);
		dis[u][v]=min(dis[u][v],(double)w);
		dis[v][u]=min(dis[v][u],(double)w);
	}
	Floyd();
	dp();
	double ans=inf;
	for (int i=0;i<=m;i++) ans=min(ans,min(f[n][i],g[n][i]));
	printf("%.2lf",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/MashiroSky/p/6159305.html