P1772 [ZJOI2006]物流运输

思路:

那么思考怎么构建\(dp\)方程
首先我们可以设\(f[i]\)表示前\(i\)天所花费的最小值
\(f[i] = min( f[i],f[j-1]+(i-j+1) \ast L+K) (1 \leq j \leq i)\)
什么意思呢 ?
就是第\(j\)天到第\(i\)天走同一条路,并且这条路和第\(j-1\)天是不同的
L就是这一天把,l到r天之内不能走的点都去掉,然后跑一边dijkstra
求一下1到m点的最短路,然后跑一下DP式子.
代码中有详解.

code

#include <bits/stdc++.h>
#include <queue>

#define N 100010
#define M 110

using namespace std;
int n, m, e, k, d;
int head[N << 1], add_edge, f[M], dis[M]; bool vis[M];
map<int, bool> ma[M];
struct node {
	int next, to, dis;
}edge[N << 1];
struct OOO {//堆优化dijkstra用品
	int po, dis;
	bool operator < (const OOO &b) const {
		return dis > b.dis;
	}
};

int read() {
	int s = 0, f = 0; char ch = getchar();
	while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return f ? -s : s;
}

void add(int from, int to, int dis) {//这就是一个很普通的前向星建图
	edge[++add_edge].next = head[from];
	edge[add_edge].to = to;
	edge[add_edge].dis = dis;
	head[from] = add_edge;
}

void dijkstra() {//很普通的堆优化dijkstra
	priority_queue<OOO> q;
	q.push((OOO){1, 0});
	dis[1] = 0;
	while (!q.empty()) {
		OOO fr = q.top(); q.pop();
		int x = fr.po;
		for (int i = head[x]; i; i = edge[i].next) {
			int to = edge[i].to;
			if (!vis[to] && dis[to] > dis[x] + edge[i].dis) {
				dis[to] = dis[x] + edge[i].dis;
				q.push((OOO){to, dis[to]}); 
			}
		}
	}
}

void init(int l) {
	for (int j = 1; j <= m; j++)//判断那个点在这个区间内不能走,然后vis表示访问过了.
		if (ma[j][l]) vis[j] = 1;
	memset(dis, 0x3f, sizeof(dis));//dijkstra用物
}

int main() {
	n = read(), m = read(), k = read(), e = read();
	for (int i = 1, x, y, de; i <= e; i++) {
		x = read(), y = read(), de = read();
		add(x, y, de), add(y, x, de);
	}
	d = read();
	for (int i = 1, dat, l, r; i <= d; i++) {
		dat = read(), l = read(), r = read();
		for (int j = l; j <= r; j++)
			ma[dat][j] = 1;//用map存一下是不是停运的马头
	}
	int ans = 0;
	memset(f, 0x3f, sizeof(f));//dp用物
	f[0] = -k;
	for (int i = 1; i <= n; i++) {
		memset(vis, 0, sizeof(vis));//不清空,火葬场。
		for (int j = i; j >= 1; j--) {
			init(j);
			dijkstra();
			int x = dis[m];
			if (x == 0x3f3f3f3f) break;
			f[i] = min(f[i], f[j - 1] + (i - j + 1) * x + k);//很简单的DP
		}
	}
	cout << f[n];
	return 0;
}
posted @ 2020-01-19 21:31  Kersen  阅读(135)  评论(0编辑  收藏  举报