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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章