Luogu P1772 [ZJOI2006]物流运输

题目由此去 P1772 [ZJOI2006]物流运输


【题目算法】 动态规划 $ + $ 最短路

【题目分析】

1 设 $ f_i $ 表示到第 $ i $ 天时所需的最小费用, $ a_{i, j}$ 表示从第 $ i $ 天到第 $ j $ 天使用同一条可行的从 $ 1 $ 到 $ n $ 的最短路。则:

$ F_i = \min (f_j + a_{j+1,i} * (i - j) + k;) $

$ Ans = f_m - k; $ (因为第一次加了一个 $ k $ )

2.计算 $ a_{i,j} $ 的值。枚举 $ i $ 和 $ j $ ,标记不能用的码头,然后用 $ dijkstra $ 求从 $ 1 $ 到 $ n $ 的最短路。

【算法步骤】

1.读入数据,用 $ w_{i,j} $ 记录第 $ i $ 天第 $ j $ 个不能用的码头;

2.求 $ a_{i,j} = dijkstra(); $

3.最后用 $ dp $ 求解


  • $ AC $ 代码
#include <cstdio>
#include <cstring>
#include <iostream>
#define INF 0x7fffffff/2
#define MAXN 105
#define ll long long
ll N,M,K,E,D,a[MAXN][MAXN],g[MAXN][MAXN],w[MAXN][MAXN],dis[MAXN],f[MAXN];
bool bj[MAXN],vst[MAXN];
int dij() {
	ll k,minn;
	for (ll i=1;i<=M;i++) {dis[i]=INF; vst[i]=0;}
	dis[1]=0;
	for (ll i=1;i<=M;i++) {
		k=0; minn=INF;
		for (ll j=1;j<=M;j++) {
			if (!vst[j]&&!bj[j]&&dis[j]<minn) {minn=dis[j]; k=j;}
		}
		if (!k) break;
		vst[k]=1;
		for (ll j=1;j<=M;j++) {
			if (g[k][j]>0&&dis[k]+g[k][j]<dis[j]) dis[j]=g[k][j]+dis[k];
		}
	}
	return dis[M];
}
void init() {
	for (ll i=1;i<=N;i++) {
		for (ll j=i;j<=N;j++) {
			memset(bj,0,sizeof(bj));
			for (ll k=i;k<=j;k++) for (ll l=1;l<=w[k][0];l++) bj[w[k][l]]=1;
			a[i][j]=dij();
		}
	}
}
void dp() {
	for (ll i=1;i<=N;i++) {
		f[i]=INF;
		for (ll j=0;j<i;j++) f[i]=min(f[j]+a[j+1][i]*(i-j)+K,f[i]);
	}
	printf("%lld",f[N]-K);
}
void read() {
	ll x,y,z,p,daya,dayb;
	scanf("%lld %lld %lld %lld",&N,&M,&K,&E);
	for (ll i=1;i<=E;i++) {scanf("%lld %lld %lld",&x,&y,&z); g[x][y]=g[y][x]=z;}
	scanf("%lld",&D);
	for (ll i=1;i<=D;i++) {
		scanf("%lld %lld %lld",&p,&daya,&dayb);
		for (ll j=daya;j<=dayb;j++) w[j][++w[j][0]]=p;
	}
}
int main() {
	read();
	init();
	dp();
	return 0;
}
posted @ 2021-07-12 16:48  铭矾  阅读(63)  评论(0)    收藏  举报