首页 > 代码库 > 【uoj262】 NOIP2016—换教室

【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;}

  

【uoj262】 NOIP2016—换教室