• bzoj1497 最小割


    题意:
    
    新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)
    
    Input
    
    输入文件中第一行有两个正整数N和M 。第二行中有N个整数描述每一个通讯中转站的建立成本,依次为P1, P2, …, PN 。以下M行,第(i + 2)行的三个数Ai, Bi和Ci描述第i个用户群的信息。所有变量的含义可以参见题目描述。
    
    Output
    
    你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。
    题意

    据说是一个很经典的最小割模型 最大权闭合子图

    我们将源点和用户连接一条收益的边,用户和两个中转站连接一条INF的边,中转站和汇点连接一条花费的边。

    首先最理想的情况就是只拿收益不拿成本,但是这显然是不可能的,所以我们建的图实际上是一个满收益成本的图。

    我们可以割用户和源点的边:放弃收益

    或者割中转站和汇点的边:加上成本。

    所以整个图的最小割就是最大收益 - 最小成本。

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 2e5 + 10;
    const int maxm = 4e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    struct Dinic{
        struct Edge{
            int from,to,cap,flow,nxt;
            Edge() {}
            Edge(int u,int v,int c,int f,int n):from(u),to(v),cap(c),flow(f),nxt(n) {}
        }edge[maxm];
        int n,s,t,E,head[maxn];
        bool vis[maxn];
        int d[maxn],cur[maxn];
        inline void AddEdge(int f,int t,int c){
            edge[++E] = Edge(f,t,c,0,head[f]);
            head[f] = E;
            edge[++E] = Edge(t,f,0,0,head[t]);
            head[t] = E;
        }
        inline void Init(int n,int s,int t){
            this -> n = n; E = -1;
            this -> s = s; head[s] = -1;
            this -> t = t; head[t] = -1;
            for(int i = 0 ; i <= n ; i ++) head[i] = -1;
        }
    
        inline bool BFS(){
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            d[s] = 0;vis[s] = 1;
            for(Q.push(s);!Q.empty();){
                int x = Q.front(); Q.pop();
                for(int nxt,i = head[x];~i;i = nxt){
                    Edge &e = edge[i]; nxt = e.nxt;
                    if(vis[e.to] || e.cap <= e.flow) continue;
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    Q.push(e.to); 
                }
            }
            return vis[t];
        }
    
        inline int DFS(const int &x,int a){
            if(x == t || a == 0) return a;
            int flow = 0,f,nxt;
            for(int &i = cur[x]; ~i; i = nxt){
                Edge &e = edge[i]; nxt = e.nxt;
                if(d[x] + 1 != d[e.to]) continue;
                f = DFS(e.to,min(a,e.cap - e.flow));
                if(f <= 0) continue;
                e.flow += f;
                edge[i ^ 1].flow -= f;
                flow += f; a -= f;
                if(!a) break;
            }
            return flow;
        }
        inline int maxFlow(){return maxFlow(s,t);}
        inline int maxFlow(int s,int t){
            int flow = 0;
            for(;BFS();){
                for(int i = 0 ;i <= n ; i ++) cur[i] = head[i];
                flow += DFS(s,INF);
            }
            return flow;
        }
    }g;
    
    int main()
    {
        Sca2(N,M);
        g.Init(N + M + 1,N + M + 1,0);
        For(i,1,N){
            int x = read();
            g.AddEdge(i,0,x);
        } 
        int sum = 0;
        For(i,1,M){
            int u,v,w;
            Sca3(u,v,w); sum += w;
            g.AddEdge(i + N,u,INF);
            g.AddEdge(i + N,v,INF);
            g.AddEdge(N + M + 1,i + N,w);
        }
        Pri(sum - g.maxFlow());
        #ifdef VSCode
        system("pause");
        #endif
        return 0;
    }
  • 相关阅读:
    选择器的用处
    全栈工程师基础知识与笔记
    9.13日笔记
    9.12笔记
    9.11Css
    学习笔记
    9.10HTLM
    redis和memcached的区别(总结)
    OO第四次博客作业
    OO第三次博客作业
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9818284.html
Copyright © 2020-2023  润新知