BZOJ_1003_[ZJOI2006]物流运输_最短路+dp

BZOJ_1003_[ZJOI2006]物流运输_最短路+dp

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1003

分析:

这种一段一段的显然要用dp求。

f[i]表示到第i天为止的最小花销。转移有f[i]=min{f[j-1]+cost[j][i]*(i-j+1)+k};

其中cost[i][j]表示从i到j天的最短路长度,spfa预处理出来。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int head[30],to[1000],nxt[1000],val[1000],cnt;
int n,m,k,t,inb[110][30],f[110],cost[110][110],can[30];
int Q[100],l,r,dis[30],inq[30];
inline void add(int u,int v,int w){
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;val[cnt]=w;    
}
int spfa(int be,int en){
    for(int i=1;i<=n;i++)can[i]=0;
    for(int i=be;i<=en;i++)
        for(int j=1;j<=n;j++)if(inb[i][j])
            can[j]=1;
    l=r=0;
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;Q[r++]=1;inq[1]=1;
    while(l^r){
        int x=Q[l++];if(l==n+10)l=0;inq[x]=0;    
        for(int i=head[x];i;i=nxt[i]){
            if(can[to[i]])continue;
            if(dis[to[i]]>dis[x]+val[i]){
                dis[to[i]]=dis[x]+val[i];
                if(!inq[to[i]]){
                    inq[to[i]]=1;Q[r++]=to[i];if(r==n+10)r=0;    
                }
            }
        }
    }
    return dis[n]>100000?-1:dis[n];
}
int main(){
    scanf("%d%d%d%d",&t,&n,&k,&m);
    int x,y,z;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
    }
    int h;
    scanf("%d",&h);
    for(int i=1;i<=h;i++){
        scanf("%d%d%d",&x,&y,&z);
        if(y>z)swap(y,z);
        for(int j=y;j<=z;j++)inb[j][x]=1;
    }
    for(int i=1;i<=t;i++){
        for(int j=i;j<=t;j++){
            cost[i][j]=spfa(i,j);
            //printf("%d\n",cost[i][j]);
        }
    }
    f[0]=0;
    for(int i=1;i<=t;i++){
        f[i]=1<<30;
        for(int j=1;j<=i;j++){
            if(cost[j][i]==-1)continue;
            f[i]=min(f[j-1]+cost[j][i]*(i-j+1)+k,f[i]);
        }
        //printf("%d\n",f[i]);
    }
    printf("%d",f[t]-k);
}

 

posted @ 2018-02-21 19:08  fcwww  阅读(168)  评论(0编辑  收藏  举报