zoukankan      html  css  js  c++  java
  • BZOJ 1497 [NOI2006]最大获利 (最小割)

    1497: [NOI2006]最大获利

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 6077  Solved: 2904
    [Submit][Status][Discuss]

    Description

    新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。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

    你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。

    Sample Input

    5 5
    1 2 3 4 5
    1 2 3
    2 3 4
    1 3 3
    1 4 2
    4 5 3

    Sample Output

    4

    HINT

    【样例说明】选择建立1、2、3号中转站,则需要投入成本6,获利为10,因此得到最大收益4。【评分方法】本题没有部分分,你的程序的输出只有和我们的答案完全一致才能获得满分,否则不得分。【数据规模和约定】 80%的数据中:N≤200,M≤1 000。 100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。

    Source

     析:好久没有写代码了,本想找个比较简单的题目,以前能够手写的现在不能直接写了,还得想想原理,还是抄比较快啊。
    具体这个题,是一个最小割,从源点向每个中转站引一条边,容量就是成本,然后从每个用户向汇点引一条边,容量是收益,然后每个站对每个用户连一条边,如果这个用户需要中转站的话,容量是无穷大。然后最后跑一次最大流最小割,用总收益减去最小割,注意是总收益,是不算成本,因为成本又不是收益,不能加。
    代码如下:
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #include <sstream>
    #include <list>
    #include <assert.h>
    #include <bitset>
    #include <numeric>
    #define debug() puts("++++")
    #define gcd(a, b) __gcd(a, b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a, b, sizeof a)
    #define sz size()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    //#define all 1,n,1
    #define FOR(i,x,n)  for(int i = (x); i < (n); ++i)
    #define freopenr freopen("in.txt", "r", stdin)
    #define freopenw freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e17;
    const double inf = 1e20;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 55000 + 10;
    const int maxm = 3e5 + 10;
    const int mod = 1e9 + 7;
    const int dr[] = {-1, 0, 1, 0};
    const int dc[] = {0, -1, 0, 1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline bool is_in(int r, int c) {
      return r >= 0 && r < n && c >= 0 && c < m;
    }
    struct Edge{
      int from, to, cap, flow;
    };
    
    struct Dinic{
      int n, m, s, t;
      vector<Edge> edges;
      vector<int> G[maxn];
      bool vis[maxn];
      int d[maxn];
      int cur[maxn];
    
      void init(int n){
        this->n = n;
        for(int i = 0; i < n; ++i)  G[i].cl;
        edges.cl;
      }
    
      void addEdge(int from, int to, int cap){
        edges.pb((Edge){from, to, cap, 0});
        edges.pb((Edge){to, from, 0, 0});
        m = edges.sz;
        G[from].pb(m - 2);
        G[to].pb(m - 1);
      }
    
      bool bfs(){
        queue<int> q;
        ms(vis, 0);  q.push(s);
        d[s] = 0;  vis[s] = 1;
        while(!q.empty()){
          int u = q.front();  q.pop();
          for(int i = 0; i < G[u].sz; ++i){
            Edge &e = edges[G[u][i]];
            if(!vis[e.to] && e.cap > e.flow){
              vis[e.to] = 1;
              d[e.to] = d[u] + 1;
              q.push(e.to);
            }
          }
        }
        return vis[t];
      }
    
      int dfs(int u, int a){
        if(u == t || a == 0)  return a;
        int flow = 0, f = 0;
        for(int &i = cur[u]; i < G[u].sz; ++i){
          Edge &e = edges[G[u][i]];
          if(d[e.to] == d[u] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0){
            e.flow += f;
            edges[G[u][i]^1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0)  break;
          }
        }
        return flow;
      }
    
      int maxflow(int s, int t){
        this->s = s;  this->t = t;
        int flow = 0;
        while(bfs()){ ms(cur, 0);  flow += dfs(s, INF); }
        return flow;
      }
    };
    Dinic dinic;
    
    int main(){
      scanf("%d %d", &n, &m);
      int ans = 0, s = 0, t = n + m + 1;
      for(int i = 1; i <= n; ++i){
        int x;  scanf("%d", &x);
        dinic.addEdge(s, i, x);
      }
      for(int i = 1; i <= m; ++i){
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        dinic.addEdge(a, i + n, INF);
        dinic.addEdge(b, i + n, INF);
        dinic.addEdge(i + n, t, c);
        ans += c;
      }
      ans -= dinic.maxflow(s, t);
      printf("%d
    ", ans);
      return 0;
    }
    

      

  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/8328895.html
Copyright © 2011-2022 走看看