zoukankan      html  css  js  c++  java
  • 正睿2020普转提【第六套】图

    T4

    题目

    给你一张带边权的有向图,一共有(N)个点, (M)条边,每个点都恰好仅有一条出边连向一个节点(可以是自己,即允许自环),于是就形成了一些环下面挂着一些树一样的基环外向树(环套树)的模样。

    睿爸会从这张图中的(1)号节点出发,一直沿着唯一的出边走,直到遇到经过的节点后停止,然后睿爸会计算一路上经过的路径和。

    睿爸可以在此这张图上修改不超过(K)条边,但修改要符合以下条件:

    1.修改后仍然是每个点仅有一条出边

    2.修改的边只能在数据给你的备选边之间挑选去替换原来的边。

    睿爸想知道修改不超过(K)条边后从(1)号点出发直到遇到经过的点的路径和最小值。

    Solution

    自环重边完全没影响。

    我们设(dis[v][tot])表示1号点经过(tot)条需替换的边到达(v)的最小路径和。

    数据范围极小,可以直接(dfs)(想不到吧,这方法比标算还快)

    记录(dfs(now, sum, tot)),表示现在在点(now),经过(tot)条需替换的边,最小路径和为(sum)的状态。

    直接暴力转移、回溯,速度杠杠的。

    (mathrm{Code:})

    #include <climits>
    #include <cstring>
    #include <iostream>
    const int N = 510, M = 2010, K = 20;
    int n, m, k;
    
    inline int read() {
        int s = 0, w = 1;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '-') c = getchar();
        if (c == '-') w = -1, c = getchar();
        while (c <= '9' && c >= '0')
            s = (s << 1) + (s << 3) + c - '0', c = getchar();
        return s * w;
    }
    template <class T>
    inline void write(T x) {
        if (x < 0) x = ~x + 1, putchar('-');
        if (x > 9) write(x / 10);
        putchar(x % 10 + 48);
        return void();
    }
    int ans = INT_MAX;
    
    struct Graph {
        int to[M], w[M], net[M], is[M];
        int fl[N], len;
        inline void inc(int x, int y, int z, int l) {
            to[++len] = y;
            w[len]    = z;
            is[len]   = l;
            net[len]  = fl[x];
            fl[x]     = len;
        }
    } G;
    int dis[N][K];
    int vis[N];
    
    void dfs(int ti, int sum, int tot) {
        if (tot > k) return void();
        if (vis[ti]) return ans = std ::min(ans, sum), void();
        if (sum >= dis[ti][tot]) return void();
        vis[ti] = 1, dis[ti][tot] = sum;
        for (int i = G.fl[ti]; i; i = G.net[i])
            dfs(G.to[i], sum + G.w[i], tot + G.is[i]);
        vis[ti] = 0;
        return void();
    }
    
    signed main() {
        freopen("trolley.in", "r", stdin);
        freopen("trolley.out", "w", stdout);
        n = read();
        m = read();
        k = read();
        memset(dis, 0x3f, sizeof(dis));
        for (int i = 1; i <= n; ++i) {
            int x = read(), y = read(), z = read();
            G.inc(x, y, z, 0);
        }
        for (int i = 1; i <= m - n; ++i) {
            int x = read(), y = read(), z = read();
            G.inc(x, y, z, 1);
        }
        dfs(1, 0, 0);
        write(ans);
        return 0;
    }
    
    

    回归正题,上面的(dfs)(ks)的时候大佬想出来的,那么正解什么样呢?

    就是一个很暴力的(dp + 最短路)

    可笑还没(dfs)跑得快

    总之就是烦而又琐。

    代码我也写了一份

    $ mathrm{Code:}$

    #include <bits/stdc++.h>
    #define mmp(x, y) std ::make_pair(x, y)
    #define fi first
    #define se second
    const int N = 510, M = 2010, K = 20;
    
    inline int read() {
        int s = 0, w = 1;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '-') c = getchar();
        if (c == '-') w = -1, c = getchar();
        while (c <= '9' && c >= '0')
            s = (s << 1) + (s << 3) + c - '0', c = getchar();
        return s * w;
    }
    int n, m, k;
    template <class T>
    inline void write(T x) {
        if (x < 0) x = ~x + 1, putchar('-');
        if (x > 9) write(x / 10);
        putchar(x % 10 + 48);
        return void();
    }
    
    struct Graph {
        int to[M], w[M], net[M];
        int fl[N], len;
        inline void inc(int x, int y, int z) {
            to[++len] = y;
            w[len]    = z;
            net[len]  = fl[x];
            fl[x]     = len;
        }
    } G;
    struct edge {
        int x, y, z;
        edge(int _x = 0, int _y = 0, int _z = 0) { x = _x, y = _y, z = _z; }
    } e[M];
    int f[N][N][K] = {};
    int tot = 0, fl[N] = {};
    int ans = INT_MAX;
    void init() {
        n = read();
        m = read();
        k = read();
        memset(f, 0x3f, sizeof(f));
        for (int i = 1; i <= n; ++i) {
            int x = read(), y = read(), z = read();
            G.inc(x, y, z);
        }
        for (int i = 1; i <= m - n; ++i) {
            int x = read(), y = read(), z = read();
            e[++tot] = edge(fl[x], y, z);
            fl[x]    = tot;
        }
    }
    void work(int st, int f[N][K]) {
        f[st][0] = 0;
        for (int i = 0; i <= k; ++i) {
            std ::priority_queue<std ::pair<int, int> > q;
            for (int j = 1; j <= n; ++j) q.push(mmp(-f[j][i], j));
            while (!q.empty()) {
                std ::pair<int, int> u = q.top();
                if (f[u.se][i] == -q.top().fi) {
                    int v = G.to[G.fl[u.se]];
                    if (v == st) v = 0;
                    if (f[u.se][i] + G.w[G.fl[u.se]] < f[v][i]) {
                        f[v][i] = f[u.se][i] + G.w[G.fl[u.se]];
                        q.push(mmp(-f[v][i], G.to[G.fl[u.se]]));
                    }
                }
                q.pop();
            }
            if (i < k) {
                for (int u = 1; u <= n; ++u)
                    for (int j = fl[u]; j; j = e[j].x) {
                        int v = e[j].y;
                        if (v == st) v = 0;
                        f[v][i + 1] = std ::min(f[v][i + 1], f[u][i] + e[j].z);
                    }
                for (int u = 1; u <= n; ++u)
                    f[u][i + 1] = std ::min(f[u][i + 1], f[u][i]);
            }
        }
    }
    main() {
        freopen("trolley.in", "r", stdin);
        freopen("trolley.out", "w", stdout);
        init();
        for (int i = 1; i <= n; ++i) work(i, f[i]);
        for (int i = 1; i <= n; ++i)
            for (int j = 0; j <= k; ++j)
                ans = std ::min(ans, f[1][i][j] + f[i][0][k - j]);
        write(ans);
        putchar(10);
        return 0;
    }
    
    
  • 相关阅读:
    IE8 "开发人员工具" 无法使用,无法显示
    Python中用OpenPyXL处理Excel表格
    calendar函数使用说明【转】
    python之fabric2.0模块学习
    Day9
    Day8
    深入super,看Python如何解决钻石继承难题——转自楚门蔡的测视界
    python/socket编程之粘包
    os模块关于目录
    Day7
  • 原文地址:https://www.cnblogs.com/yywxdgy/p/13062459.html
Copyright © 2011-2022 走看看