PAT A1018 Public Bike Management

思路:先使用Dijkstra算法求出最短路径,使用pre记录最短路径中每个结点的前驱。

再使用DFS从目标结点开始倒序遍历到PBMC,求出具有最小Need同时具有最小remain的路径。

注意,倒序遍历到PBMC之后才开始计算need和remain,而且当出现remain不足当前站点所需自行车数量时,一定需要从PBMC带来自行车,也就是need单调增加,不能从后面的结点中得到的remain再补贴前面的结点。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 505;
const int INF = 1e9;

int Cmax, N, Sp, M;
int minRemain = INF, minNeed = INF;
int G[maxn][maxn], weight[maxn], d[maxn];
bool visit[maxn];
vector<int> pre[maxn], temp, ans;

void Dijkstra(int s) {
    fill(d, d + maxn, INF);
    d[s] = 0;
    for(int i = 0; i < N; i++) {
        int u = -1, MIN = INF;
        for(int j = 0; j <= N; j++) 
            if(!visit[j] && d[j] < MIN) {
                u = j;
                MIN = d[j];
            }
        if(u == -1) return;
        visit[u] = true;
        for(int v = 0; v <= N; v++) 
            if(!visit[v] && G[u][v] != INF) {
                if(d[u] + G[u][v] < d[v]) {
                    d[v] = d[u] + G[u][v];
                    pre[v].clear();
                    pre[v].push_back(u);
                } else if(d[u] + G[u][v] == d[v]) {
                    pre[v].push_back(u);
                }
            }
    }
}

void DFS(int s) {
    if(s == 0) {
        temp.push_back(s);
        int need = 0, remain = 0;
        for(int i = temp.size() - 1; i >= 0; i--) {
            int u = temp[i];
            if(weight[u] > 0) remain += weight[u];
            else {
                if(remain > abs(weight[u]))
                    remain -= abs(weight[u]);
                else {
                    need += abs(weight[u]) - remain;
                    remain = 0;
                }
            }
        }
        if(need < minNeed) {
            minNeed = need;
            minRemain = remain;
            ans = temp;
        } else if(need == minNeed && remain < minRemain) {
            minRemain = remain;
            ans = temp;
        } 
        temp.pop_back();
        return;
    }
    temp.push_back(s);
    for(int i = 0; i < pre[s].size(); i++)
        DFS(pre[s][i]);
    temp.pop_back();
}

int main() {
    cin >> Cmax >> N >> Sp >> M;
    for(int i = 1; i <= N; i++) {
        cin >> weight[i];
        weight[i] -= Cmax / 2;
    }
    int u, v, w;
    fill(G[0], G[0] + maxn * maxn, INF);
    for(int i = 0; i < M; i++) {
        cin >> u >> v >> w;
        G[u][v] = G[v][u] = w;
    }
    Dijkstra(0);
    DFS(Sp);
    printf("%d ", minNeed);
    for(int i = ans.size() - 1; i >= 0; i--) {
        printf("%d", ans[i]);
        if(i > 0) printf("->");
    }
    printf(" %d\n", minRemain);
    return 0;
}