• CodeForces-1082G Increasing Frequency


    题目链接:CodeForces-1082G Increasing Frequency

    题意

    有$n$个点,$m$条边,每个点和每条边都有一个权值,要求你从所给的图中选出一个子图,使得$sum{val_{edges}}-sum{val_{vertices}}$的值最大,子图的边集需满足:每条边关联的两个结点都在子图的点集中。


    思路

    闭合子图是选了结点 $u$ ,那么 $u$ 的所有后继结点也要选,而这道题是选了一条边,那么这条边的两个端点也要选,根据这个性质,把原图的边转换为结点,边权转换为点权,向两个端点连有向边,这样两个端点成为代表边的结点的后继结点,题目也就转换为了闭合子图问题。原图结点点权对答案贡献为负,所以点权取相反数改为负权值,边权对答案贡献为正,所以代表边的结点仍为正权值,题目即为求以上构建出的这个图的最大权闭合子图。

    最大权闭合子图详解:传送门


    代码实现

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using std::queue;
    typedef long long LL;
    const int INF = 0x3f3f3f3f, N = 5010, M = 50010;
    int head[N], d[N];
    int n, m, s, t, tot;
    LL maxflow;
    struct Edge
    {
        int to, cap, nex;
    } edge[M];
    queue<int> q;
    void add(int x, int y, int z) {
        edge[++tot].to = y, edge[tot].cap = z, edge[tot].nex = head[x], head[x] = tot;
        edge[++tot].to = x, edge[tot].cap = 0, edge[tot].nex = head[y], head[y] = tot;
    }
    bool bfs() { // 在残存网络上构造分层图
        memset(d, 0, sizeof(d));
        while (q.size()) q.pop();
        q.push(s); d[s] = 1;
        while (q.size()) {
            int x = q.front(); q.pop();
            for (int i = head[x]; i; i = edge[i].nex) {
                int v = edge[i].to;
                if (edge[i].cap && !d[v]) {
                    q.push(v);
                    d[v] = d[x] + 1;
                    if (v == t) return true;
                }
            }
        }
        return false;
    }
    int dinic(int x, int flow) {  // 在当前分层图上增广
        if (x == t) return flow;
        int rest = flow, k;
        for (int i = head[x]; i && rest; i = edge[i].nex) {
            int v = edge[i].to;
            if (edge[i].cap && d[v] == d[x] + 1) {
                k = dinic(v, std::min(rest, edge[i].cap));
                if (!k) d[v] = 0;  // 剪枝,去掉增广完毕的点(当前弧优化)
                edge[i].cap -= k;
                edge[i^1].cap += k;
                rest -= k;
            }
        }
        return flow - rest;
    }
    
    int main() {
        while (~scanf("%d %d", &n, &m)) {
            s = 0, t = n + m + 1;
            tot = 1, maxflow = 0;
            memset(head, 0, sizeof(head));
            for (int i = 1, val; i <= n; i++) {
                scanf("%d", &val);
                add(i, n + m + 1, val);
            }
            LL sum = 0;
            for (int i = 1, u, v, val; i <= m; i++) {
                scanf("%d %d %d", &u, &v, &val);
                sum += val;
                add(0, n + i, val);
                add(n + i, u, INF);
                add(n + i, v, INF);
            }
            while (bfs()) maxflow += dinic(s, INF);
            printf("%I64d
    ", sum - maxflow);
        }
        return 0;
    }
    View Code
    作者:_kangkang
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    SSH框架整合实现Java三层架构实例(一)
    【面试】MySQL的事务和索引
    Spring在web开发中的应用
    Freemarker 页面静态化技术使用入门案例
    jQuery EasyUI window窗口使用实例
    zTree树形菜单交互选项卡效果实现
    zTree树形菜单使用实例
    jQuery EasyUI 选项卡面板tabs使用实例精讲
    jQuery EasyUI 折叠面板accordion的使用实例
    jQuery EasyUI布局容器layout实例精讲
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11314186.html
Copyright © 2020-2023  润新知