• hiho# 1398 最大权闭合子图 网络流


    题目传送门

    题意:给出n个活动,m个人,请人需要花费$a[i]$的钱,举办一次活动可以赚$b[i]$的钱,但是需要固定的几个人在场,一个人只需要请一次后就必定在场,问最大收益。

    思路:

      下列结论来自hihocoder的例题

      下面不加证明的给出几个概念和结论。

      1)闭合子图:给定一个有向图,从中选择一些点组成一个点集V。对于V中任意一个点,其后续节点都仍然在V中。比如:

      

          在这个图中有8个闭合子图:∅,{3},{4},{2,4},{3,4},{1,3,4},{2,3,4},{1,2,3,4}

      2) 最大权闭合子图:如上图的二分图,A部权值为正,B部权值为负,要求闭合子图权值最大,即为最大权闭合子图。

      3)最大权闭合子图求法:首先建立源点s和汇点t,将源点s与所有权值为正的点相连,容量为权值;将所有权值为负的点与汇点t相连,容量为权值的绝对值;权值为0的点不做处理;同时将原来的边容量设置为无穷大。$ans=权值为正的点的和-最小割$

    此题显然就是求一个最大权闭合子图。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    
    typedef long long ll;
    
    const ll INFLL = 0x3f3f3f3f3f3f3f3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 510;
    
    struct Edge {
        int to, flow, nxt;
        Edge(){}
        Edge(int to, int nxt, int flow):to(to),nxt(nxt), flow(flow){}
    }edge[maxn * maxn * 2];
    
    int head[maxn*2], dep[maxn*2];
    int S, T;
    int N, n, m, tot;
    void init(int n)
    {
        N=n;
        for (int i = 0; i <= N; ++i) head[i] = -1;
        tot = 0;
    }
    
    void addv(int u, int v, int w, int rw = 0)
    {
        edge[tot] = Edge(v, head[u], w); head[u] = tot++;
        edge[tot] = Edge(u, head[v], rw); head[v] = tot++;
    }
    
    bool BFS()
    {
        for (int i = 0; i <= N; ++i) dep[i] = -1;
        queue<int>q;
        q.push(S);
        dep[S] = 1;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = edge[i].nxt)
            {
                
                if (edge[i].flow && dep[edge[i].to] == -1)
                {
                    dep[edge[i].to] = dep[u] + 1;
                    q.push(edge[i].to);
                }
            }
        }
        return dep[T] < 0 ? 0 : 1;
    }
    
    int DFS(int u, int f)
    {
        if (u == T || f == 0) return f;
        int w, used = 0;
        for (int i = head[u]; ~i; i = edge[i].nxt)
        {
            if (edge[i].flow && dep[edge[i].to] == dep[u] + 1)
            {
                w = DFS(edge[i].to, min(f - used, edge[i].flow));
                edge[i].flow -= w;
                edge[i ^ 1].flow += w;
                used += w;
                if (used == f) return f;
            }
        }
        if (!used) dep[u] = -1;
        return used;
    }
    
    int Dicnic()
    {
        int ans = 0;
        while (BFS())
        {
            ans += DFS(S, INF);
        }
        return ans;
    }
    
    int main(){
        cin>>n>>m;
        T=n+m+1;
        init(T);
        S=0;
        for(int i=1;i<=m;i++){
            int w;
            scanf("%d",&w);
            addv(i+n,T,w);
        }
        int res=0;
        for(int i=1;i<=n;i++){
            int w,k;
            scanf("%d%d",&w,&k);
            addv(S,i,w);
            res+=w;
            while(k--){
                scanf("%d",&w);
                addv(i,n+w,INF);
            }
        }
        int ans=res-Dicnic();
        printf("%d
    ",ans);
    }
  • 相关阅读:
    IOS总结_无需自己定义UITabbar也可改变UITabbarController的背景和点击和的颜色
    破解中国电信华为无线猫路由(HG522-C)自己主动拨号+不限电脑数+iTV
    HDUJ 2074 叠筐 模拟
    CSRF——攻击与防御
    Ant命令行操作
    C#软件开发实例.私人订制自己的屏幕截图工具(七)加入放大镜的功能
    qemu-kvm-1.1.0源代码中关于迁移的代码分析
    FileSystemWatcher使用方法具体解释
    configure交叉编译
    海量图片存储策略
  • 原文地址:https://www.cnblogs.com/mountaink/p/10673990.html
Copyright © 2020-2023  润新知