[BZOJ4720][NOIP2016] 换教室

link

$solution:$

考虑 $f(i,j,k)$ 表示前 $i$ 个时间中申请 $j$ 个的最小距离期望,且是否申请。

然后分别讨论 $i-1$ 与$i$ 换还是不换且是否成功即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<climits>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int N=2001;
const int M=2001;
const int MAXN=2001;
int head[MAXN],n,m,v,e,cnt;
struct node{
    int u,v,w,nex;
}x[180001];
priority_queue<pair<int,int> > que;
void add(int u,int v,int w){
    x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
int A[MAXN],B[MAXN],dis[MAXN],Dis[MAXN][MAXN],vis[MAXN];
double p[MAXN],f[N][M][2];
void dijkstra(int S){
    memset(vis,0,sizeof(vis));
    memset(dis,127/3,sizeof(dis));dis[S]=0;
    que.push(make_pair(0,S));
    while(!que.empty()){
        int xx=que.top().second;que.pop();
        if(vis[xx]) continue;
        Dis[S][xx]=dis[xx];
        vis[xx]=1;
        for(int i=head[xx];i!=-1;i=x[i].nex){
            if(dis[x[i].v]>dis[xx]+x[i].w){
                dis[x[i].v]=dis[xx]+x[i].w;
                que.push(make_pair(-dis[x[i].v],x[i].v));
            }
        }
    }return;
}
int main(){
    //freopen("2.in","r",stdin);
    memset(head,-1,sizeof(head));
    n=read(),m=read(),v=read(),e=read();
    for(int i=1;i<=n;i++) A[i]=read();
    for(int i=1;i<=n;i++) B[i]=read();
    for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
    memset(Dis,127/3,sizeof(Dis));
    for(int i=1;i<=v;i++) Dis[i][i]=0;
    for(int i=1;i<=e;i++){int u=read(),v=read(),w=read();Dis[u][v]=min(Dis[u][v],w);Dis[v][u]=Dis[u][v];}
    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]);
    for(int i=1;i<=n;i++) dijkstra(i);
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=(double)INT_MAX;
    double minn=f[0][0][0];
    f[1][0][0]=0,f[1][1][1]=0;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=m;j++){
            f[i][j][0]=min( f[i-1][j][1]+ p[i-1]*Dis[B[i-1]][A[i]] + (1-p[i-1])*Dis[A[i-1]][A[i]] , f[i-1][j][0]+Dis[A[i-1]][A[i]] );
            if(j!=0) f[i][j][1]=min( f[i-1][j-1][1] + p[i-1]*p[i]*Dis[B[i-1]][B[i]] + p[i-1]*(1-p[i])*Dis[B[i-1]][A[i]] + (1-p[i-1])*p[i]*Dis[A[i-1]][B[i]] + (1-p[i-1])*(1-p[i])*Dis[A[i-1]][A[i]],f[i-1][j-1][0] + p[i]*Dis[A[i-1]][B[i]] + (1-p[i])*Dis[A[i-1]][A[i]]);
            //printf("f(%d,%d,0):%.3lf f(%d,%d,1):%.3lf\n",i,j,f[i][j][0],i,j,f[i][j][1]);
        }
    }
    //for(int i=0;i<=m;i++) printf("%.2lf %.2lf\n",f[n][i][0],f[n][i][1]);
    for(int i=0;i<=m;i++) minn=min(minn,min(f[n][i][0],f[n][i][1]));
    printf("%.2lf\n",minn);
    return 0;
}/*
3 2 3 3
2 1 2
1 2 1
0.8 0.2 0.5 
1 2 5
1 3 3
2 3 1
*/
View Code

 

posted @ 2019-05-10 22:47  siruiyang_sry  阅读(166)  评论(0编辑  收藏  举报