BZOJ1003(ZJOI2006)[物流运输]--最短路+DP

【链接】
bzoj1003

【解题报告】

定义 gi,j 表示 i ~j这段时间的最短路径。

fi 表示第 i 的总成本。

可以得转移方程fi=fj+K+gj+1,i(ij)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=105,maxm=805,maxv=25;
int T,n,P,m,D,tot,g[maxn][maxn],que[maxn],dst[maxn],lnk[maxn],son[maxm],nxt[maxm],w[maxm];
bool vis[maxn],pd[maxn],flg[maxn][maxv];
LL f[maxn];
inline char nc()
{
    static char buf[100000],*l,*r;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
inline int Read()
{
    int res=0; char ch=nc();
    while (ch<'0'||ch>'9') ch=nc();
    while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=nc();
    return res;
}
void Add(int x,int y,int z) {w[++tot]=z; son[tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;}
int Spfa(int s,int t)
{
    memset(dst,63,sizeof(dst));
    memset(pd,1,sizeof(pd));
    memset(vis,0,sizeof(vis));
    for (int i=s; i<=t; i++)
     for (int j=1; j<=n; j++)
      if (!flg[i][j]) pd[j]=0;
    int hed=0,til=1; que[1]=1; dst[1]=0; vis[1]=1;
    while (hed!=til)
    {
        int x=que[hed=(hed+1)%maxn]; vis[x]=0;
        for (int j=lnk[x]; j; j=nxt[j])
         if (pd[son[j]]&&dst[x]+w[j]<=dst[son[j]])
          {
            dst[son[j]]=dst[x]+w[j];
            if (!vis[son[j]])
             {
                vis[son[j]]=1; que[til=(til+1)%maxn]=son[j];
                if (dst[que[til]]<dst[que[(hed+1)%maxn]]) swap(que[til],que[(hed+1)%maxn]);
             }
          }
    }
    return dst[n];
}
int main()
{
    freopen("1003.in","r",stdin);
    freopen("1003.out","w",stdout);
    T=Read(); n=Read(); P=Read(); m=Read(); tot=0;
    for (int i=1,x,y,z; i<=m; i++) x=Read(),y=Read(),z=Read(),Add(x,y,z),Add(y,x,z);
    D=Read(); memset(flg,1,sizeof(flg));
    for (int i=1; i<=D; i++)
    {
        int x=Read(),s=Read(),t=Read();
        for (int j=s; j<=t; j++) flg[j][x]=0;
    }
    for (int i=1; i<=T; i++)
     for (int j=1; j<=T; j++) g[i][j]=Spfa(i,j);
    for (int i=1; i<=T; i++)
    {
        f[i]=(LL)g[1][i]*i;
        for (int j=1; j<i; j++) f[i]=min(f[i],f[j]+P+(LL)g[j+1][i]*(i-j));
    }
    printf("%lld\n",f[T]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值