2022杭电多校第四场 Link with Running

Problem - 7175 Link with Running

题意:给定 \(n\) 个点 \(m\) 条边的有向图,走每条边需要花费 \(e_i\) 的能量且得到 \(p_i\) 的分数,问从1号点开始走到n号点,当花费最少时得分最多,输出花费和得分,保证答案存在。

知识点:缩点,最短路

首先的想法就是dijkstra的过程中同时计算最短路和得分,但是由于0费用的存在,答案是跑不对的,例如下面这个样例

3 3
1 2 0 1
1 3 0 2
2 3 0 3

如果你的dijkstra不是加了vis数组判重的,那你会跑得过去,否则是错的,但是我们需要加这个vis判重,就是因为有0环的存在,如果不加就T了

问题就是出在0环的地方,我们考虑将0环处理掉

值得注意的是,我们用到的边都是最短路边,所以我们可以先跑一遍最短路处理出最短路图

然后在0环肯定出现在最短路图上,我们直接tarjan缩点,使其变成DAG,然后在DAG上DP即可。

#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, int> PLI;
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}

struct node {
    int nex;
    int cost, val;
};

int dfn[N], low[N], timeStamp;
int scc_cnt, sz[N], idx[N];
int stk[N], tt, n;
int deg[N];
bool in_stk[N];
LL dp[N];
LL dis[N];
vector<node> g1[N], g2[N], g3[N];
void init() {
    timeStamp = scc_cnt = tt = 0;
    for (int i = 1; i <= n; i ++ ) {
        g1[i].clear(), g2[i].clear(), g3[i].clear();
        in_stk[i] = false;
        dp[i] = deg[i] = 0;
        dfn[i] = low[i] = 0;
        sz[i] = idx[i] = 0;
    }
}
void dijkstra() {
    for (int i = 1; i <= n; i ++ ) dis[i] = 1e18;
    dis[1] = 0;
    priority_queue<PLI, vector<PLI>, greater<PLI>> q;
    q.push({dis[1], 1});
    vector<bool> vis(n + 1);
    while (!q.empty()) {
        auto t = q.top(); q.pop();
        int u = t.second;
        if (vis[u]) continue;
        vis[u] = true;
        for (auto ite : g1[u]) {
            int v = ite.nex, w = ite.cost;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                q.push({dis[v], v});
            }
        }
    }
}
void tarjan(int u) {
    dfn[u] = low[u] = ++timeStamp;
    stk[++ tt] = u, in_stk[u] = true;
    for (auto ite : g2[u]) {
        int v = ite.nex;
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (in_stk[v]) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        int y;
        scc_cnt ++;
        do {
            y = stk[tt --];
            sz[scc_cnt] ++;
            idx[y] = scc_cnt;
            in_stk[y] = false;
        } while (y != u);
    }
}
void topSort() {
    queue<int> q;
    for (int i = 1; i <= scc_cnt; i ++ ) if (deg[i] == 0) q.push(i);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (auto ite : g3[u]) {
            int v = ite.nex, w = ite.val;
            if (dp[v] < dp[u] + w) dp[v] = dp[u] + w;
            deg[v] --;
            if (deg[v] == 0) q.push(v);
        }
    }
}
inline void solve() {
    int m; cin >> n >> m;
    init();
    while (m -- ) {
        int u, v, w, p;
        cin >> u >> v >> w >> p;
        g1[u].push_back({v, w, p});
    }
    dijkstra();
    for (int i = 1; i <= n; i ++ ) {
        for (auto ite : g1[i]) {
            if (dis[ite.nex] == dis[i] + ite.cost) {
                g2[i].push_back(ite);
            }
        }
    }
    for (int i = 1; i <= n; i ++ ) if (!dfn[i]) tarjan(i);
    set<PII> s;
    for (int i = 1; i <= n; i ++ ) {
        for (auto ite : g2[i]) {
            int v1 = idx[i], v2 = idx[ite.nex];
            if (v1 == v2) continue;
            deg[v2] ++;
            g3[v1].push_back({v2, ite.cost, ite.val});
        }
    }
    topSort();
    cout << dis[n] << ' ' << dp[idx[n]] << endl;
}
signed main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    auto now = clock();
#endif
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cout << fixed << setprecision(2);
    int T; cin >> T;
    while (T -- )
        solve();
#ifdef DEBUG
    cout << "============================" << endl;
    cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}
posted @ 2022-08-01 11:07  Time_Limit_Exceeded  阅读(23)  评论(0编辑  收藏  举报