#SPFA,动态规划#洛谷 1772 [ZJOI2006]物流运输

题目


分析

改变航线可以通过费用提前计算实现,
这样就不用增加次数这一维,也没有必要,
\(dp[i]\)表示前\(i\)天的总费用
那么\(dp[i]=\min\{dp[j-1]+(i-j+1)*mindis+cost\}\)
记录每个点在\([j,i]\)是否能被经过倒序就不用清空次数过多
再套一个SPFA求最短路径即可


代码

#include <cstdio>
#include <cctype>
#include <queue>
#include <cstring>
#define rr register
using namespace std;
struct node{int y,w,next;}e[1001];
int dis[21],ls[21],v[21]; queue<int>q;
int dp[101],lim[21],limit[101][21],k=1,day,n,m,cost;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline signed spfa(){
    memset(dis,42,sizeof(dis));
    dis[1]=0,v[1]=1,q.push(1);
    while (q.size()){
        rr int x=q.front(); q.pop();
        for (rr int i=ls[x];i;i=e[i].next)
        if (dis[e[i].y]>dis[x]+e[i].w&&!lim[e[i].y]){
            dis[e[i].y]=dis[x]+e[i].w;
            if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
        }
        v[x]=0;
    }
    return dis[n];
}
signed main(){
	day=iut(),n=iut(),cost=iut(),m=iut();
	for (rr int i=1;i<=m;++i){
		rr int x=iut(),y=iut(),w=iut();
		e[++k]=(node){y,w,ls[x]},ls[x]=k,
		e[++k]=(node){x,w,ls[y]},ls[y]=k;
	}
	for (rr int Q=iut();Q;--Q){
		rr int x=iut(),l=iut(),r=iut();
		for (rr int j=l;j<=r;++j) limit[j][x]=1;
	}
	memset(dp,42,sizeof(dp));
	dp[0]=-cost;
	for (rr int i=1;i<=day;++i){
		for (rr int j=1;j<=n;++j) lim[j]=0;
		for (rr int j=i;j>=1;--j){
			for (rr int k=1;k<=n;++k)
			    lim[k]|=limit[j][k];
			rr int now=spfa();
			if (now>=7e8) break;
			dp[i]=min(dp[i],dp[j-1]+(i-j+1)*now+cost);
		}
	}
	return !printf("%d",dp[day]);
}
posted @ 2021-03-05 18:37  lemondinosaur  阅读(34)  评论(0编辑  收藏  举报