bzoj1003

这道题一看到之后,第一感觉就是:最短路???但是贪心肯定是不行de

偷偷告诉你们一个经验,当你做题时,第一印象想到贪心,但这题显然不能贪心,多半正解是dp

那怎么更新呢?我们知道,如果存在某种走法虽然代价十分小,但适用范围很窄,照样说明不了什么

于是我们存储一段时间中都可以适用的那条最短路径(虽然可能会没有)

然后就去dp就好啦~

#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
#define M 24
#define N 110
struct EDGE {
	int to, val, next;
}edge[M*M];
struct IMPORTANT {
	int num, a[M];
}p[N];
bool v[M], flag[M];
int cost[N][N], head[M], dis[M], f[N];
int n, m, k, e, cnt, s;
inline void add(int x, int y, int z) {
	edge[++cnt].to = y; edge[cnt].val = z;
	edge[cnt].next = head[x]; head[x] = cnt;
	return ;
}
inline int spfa(int x, int y) {
	memset(v, false, sizeof(v));
	for(int i = x; i <= y; ++i)
		for(int j = 1; j <= p[i].num; ++j)
			v[p[i].a[j]] = true;
	queue<int>Q;
	memset(flag, false, sizeof(flag));
	Q.push(1); memset(dis, 127, sizeof(dis)); dis[1] = 0;
	flag[1] = true; 
	while(!Q.empty()) {
		int now = Q.front(); Q.pop(); 
		flag[now] = false;
		for(int i = head[now]; i; i = edge[i].next) {
			int to = edge[i].to, val = edge[i].val;
			if(v[to]) continue;
			if(dis[now] + val < dis[to]) {
				dis[to] = dis[now] + val;
				if(!flag[to]) {Q.push(to); flag[to] = true;}
			}
		}
	}
	return dis[m];
}
int main() {
	freopen("1003.in", "r", stdin);
	scanf("%d%d%d%d", &n, &m, &k, &e);
	memset(head, 0, sizeof(head)); cnt = 0;
	for(int i = 1; i <= e; ++i) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w); add(v, u, w);
	}
	scanf("%d", &s); memset(p, 0, sizeof(p));
	for(int i = 1; i <= s; ++i) {
		int ai, fr, to;
		scanf("%d%d%d", &ai, &fr, &to);
		for(int j = fr; j <= to; ++j) {
			p[j].num++;
			p[j].a[p[j].num] = ai;
		}
	}
	for(int i = 1; i <= n; ++i)
		for(int j = i; j <= n; ++j) {
				cost[i][j] = spfa(i, j);
				if(cost[i][j] <= 999999999) cost[i][j]*= (j - i + 1);
		}
	for(int i = 1; i <= n; ++i) f[i] = cost[1][i];
	for(int i = 2; i <= n; ++i) {
		for(int j = 1; j < i; ++j) f[i] = min(f[i], f[j] + cost[j + 1][i] + k);
	}
	printf("%d", f[n]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值