• 2020牛客多校第五场A-Portal


    https://ac.nowcoder.com/acm/contest/5670/A

    题意

    有一个n个点m条边的带权图,你一开始在1号点,你要按顺序完成k个任务,第i个任务是先去a[i]再走
    到b[i]。当你走到一个点上的时候,你可以在这个点创建一个传送门。当同时存在两个传送门的时候,
    你可以在传送门之间不耗代价地传送。如果已经存在了两个传送门,你想再创建一个,就必须选择之前
    的一个传送门关掉(关掉这个操作不耗时间,并且是远程操作,不需要走过去)。问完成所有任务的最
    短总行走距离。

    题解

    我们考虑两个传送门的位置,其中一个传送门的位置其实是没有用的,我们随时可以在当前所在的位置开一个传送门,而不是走到一个传送门的位置再进行传送。

    目标是要走完所有的(2k)个点,我们把任务拆开,设状态(f[i][q])表示完成i个任务,这次的传送门设在q的最小花费,那么有以下情况

    1. 直接从c[i-1]走到c[i]
    2. 从c[i-1]走到q,在q开启传送门,枚举上一次传送门的位置p,从q传送到p,再从p走到c[i]
    3. 从c[i-1]走到q,在q开启传送门,直接从q走到c[i]
    4. 从c[i-1]传送到p,从p走到q,在q开启传送门,再从q走到c[i]

    Floyd预处理出两点间的最短距离,直接转移即可

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct READ {
        inline char read() {
        #ifdef _WIN32
            return getchar();
        #endif
            static const int IN_LEN = 1 << 18 | 1;
            static char buf[IN_LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            static char c11, boo;
            for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
                if(c11 == -1) return *this;
                boo |= c11 == '-';
            }
            for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
            boo && (x = -x);
            return *this;
        }
    } in;
    
    const int N = 350;
    ll G[N][N];
    int a[N<<1];
    ll f[N<<1][N];
    const ll inf = 0x3f3f3f3f3f3f3f3f;
    int main() {
        int n, m, k; in >> n >> m >> k;
        memset(G, inf, sizeof(G));
        for (int i = 1; i <= m; i++) {
            int u, v; ll w; in >> u >> v >> w;
            G[u][v] = min(G[u][v], w);
            G[v][u] = min(G[v][u], w);
        }
        for (int i = 1; i <= n; i++) G[i][i] = 0;
        k *= 2;
        for (int i = 1; i <= k; i++) in >> a[i];
        a[0] = 1;
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
                }
            }
        }
        memset(f, inf, sizeof(f));
        f[0][1] = 0;
        for (int i = 1; i <= k; i++) {
            for (int p = 1; p <= n; p++) {
                if (f[i-1][p] != inf) f[i][p] = min(f[i][p], f[i-1][p] + G[a[i-1]][a[i]]);
                for (int q = 1; q <= n; q++) {
                    f[i][q] = min(f[i][q], f[i-1][p] + G[a[i-1]][q] + G[p][a[i]]);
                    f[i][q] = min(f[i][q], f[i-1][p] + G[a[i-1]][q] + G[q][a[i]]);
                    f[i][q] = min(f[i][q], f[i-1][p] + G[p][q] + G[q][a[i]]);
                }
            }
        }
        ll ans = inf;
        for (int i = 1; i <= n; i++) ans = min(ans, f[k][i]);
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    分析NGINX 健康检查和负载均衡机制
    基于ASIO的协程库orchid简介
    基于ASIO的协程与网络编程
    Boost.Asio技术文档
    Linux升级命令yum upgrade和yum update的区别
    yum和apt-get的用法和区别
    Linux-centos7设置静态IP地址
    Linux-各种姿势(lessvi等)打开各种类型的文件(txt/csv/xlsx等)出现不能打开(全乱码、部分乱码、二进制文件等)的问题
    Excel-vlookup(查找值,区域范围,列序号,0)如何固定住列序列号,这样即使区域范围变动也不受影响
    EXCEL-名称管理器
  • 原文地址:https://www.cnblogs.com/artoriax/p/13595991.html
Copyright © 2020-2023  润新知