这道题一看到之后,第一感觉就是:最短路???但是贪心肯定是不行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;
}