【bzoj1003】【ZJOI2006】【物流运输】【最短路】【动态规划】

32 篇文章 0 订阅
22 篇文章 0 订阅

题目大意

给出一幅无向图(点数<=20),在n天内,有某些点在某段时间不能经过,求n天最短路之和,每相邻两天所走路不同将付出额外代价k,求最小代价。

题解

用单最短路算法求出任意一段时间用同样路径的花费。f[i]表示1到i天的花费,f[j]=min{f[i]+cost[i+1][j]*(j-i)+k}(j>i)。
#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=100,maxm=20;
int n,m,k,e,d,dis[maxm+10],queue[maxm*5+10],map[maxm+10][maxm+10],unable[maxm+10][maxn+10],
    cost[maxn+10][maxn+10],f[maxn+10];
bool inqueue[maxm+10];
int spfa(int u,int v){
    memset(dis,63,sizeof(dis));
    dis[1]=0;int head=0,tail=0;
    inqueue[queue[++tail]=1]=1;
    while(head!=tail){
        int now=queue[++head];
        inqueue[now]=0;
        fo(i,1,m)
            if(map[now][i]&&(dis[now]+map[now][i]<dis[i])&&(unable[i][v]-unable[i][u-1]==0)){
                dis[i]=dis[now]+map[now][i];
                if(!inqueue[i])inqueue[queue[++tail]=i]=1;
            }
    }
    return dis[m];
}
int main(){
    scanf("%d%d%d%d",&n,&m,&k,&e);
    memset(map,63,sizeof(map));
    fo(i,1,e){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        map[u][v]=map[v][u]=min(map[u][v],w);
    }
    scanf("%d",&d);
    fo(i,1,d){
        int p,a,b;scanf("%d%d%d",&p,&a,&b);
        fo(j,a,b)unable[p][j]=1;
    }
    fo(i,1,m)
        fo(j,1,n)unable[i][j]+=unable[i][j-1];
    fo(i,1,n)
        fo(j,i,n)
            cost[i][j]=spfa(i,j);
    memset(f,63,sizeof(f));f[0]=-k;int inf=f[1];
    fo(i,1,n)
        fo(j,0,i-1)
            if((f[j]!=inf)&&(cost[j+1][i]!=inf))f[i]=min(f[i],f[j]+cost[j+1][i]*(i-j)+k);
    printf("%d",f[n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值