【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; }
This passage is made by MashiroSky.