ZJOI2006

题目大意

就是说,你需要跑次最短路,然后对于某些时间,有些点是无法到达的
然后如果你跑路的路径发生了改变的话,那么对于每次改变都会有 的花费

分析

那么显然贪心是错误的,考虑动态规划
表示跑到第 天的最小花费,那么最后的答案显然是
那么现在考虑转移:
就是说从第 天开始一直到第 天都是同一条路线,然后花费了 的代价改变了一下这个路线,这个 应该是很显然的

Code

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 1e2 + 10;
const int maxm = 1e4 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int Size = (sizeof (int)) * maxn;

inline int __read()
{
    int x(0), t(1);
    char o (getchar());
    while (o < '0' || o > '9') {
        if (o == '-') t = -1;
        o = getchar();
    }
    for (; o >= '0' && o <= '9'; o = getchar()) {
        x = (x << 1) + (x << 3) + (o ^ 48);
    }
    return x * t;
}

int n, m, k, e, cur;
int head[maxn], edge[maxm], lst[maxm], cost[maxm];
int dis[maxn], dp[maxn];
bool vis[maxn], in_q[maxn], flag[maxn][maxn];

deque <int> Q;

inline int SPFA()
{
    memset (dis, 0x3f, Size);
    Q.push_back(1);
    dis[1] = 0;
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop_front();
        in_q[u] = 0;
        for (int i = head[u]; i; i = lst[i]) {
            int v = edge[i];
            if (dis[v] <= dis[u] + cost[i] || vis[v]) continue;
            dis[v] = dis[u] + cost[i];
            if (in_q[v]) continue;
            if (Q.empty() || dis[v] <= dis[Q.front()]) Q.push_front(v);
            else Q.push_back(v);
            in_q[v] = 1;
        }
    }
    return dis[m];
}

inline void addedge(int u, int v, int w)
{
    lst[++cur] = head[u];
    head[u] = cur;
    edge[cur] = v;
    cost[cur] = w;
}

inline int min(int x, int y)
{
    if (x < y) return x;
    return y;
}

int main()
{
    n = __read(), m = __read(), k = __read(), e = __read();
    while (e--) {
        int a = __read(), b = __read(), c = __read();
        addedge(a, b, c), addedge(b, a, c);
    }

    e = __read();
    while (e--) {
        int a = __read(), b = __read(), c = __read();
        for (int i = b; i <= c; ++i) flag[i][a] = 1;
    }

    memset (dp, 0x3f, Size);
    dp[0] = -k;

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) vis[j] = 0;
        for (int j = i; j >= 1; --j) {
            for (int k = 1; k <= m; ++k)
                if (flag[j][k]) vis[k] = 1;
            int temp = SPFA();
            if (temp == inf) break;
            dp[i] = min(dp[i], dp[j - 1] + (i - j + 1) * temp + k);
        }
    }

    printf ("%d\n", dp[n]);
}