• SPOJ PROFIT Maximum Profit (最大闭合权子图,最小割)


    题目:

    http://www.spoj.com/problems/PROFIT/

    题意:

    n个中转站,每个站建立花费Xi

    m个客户,每个客户需要中转站Ai,Bi,获得收益为Ci

    求最大收益

    最大闭合权子图(详见《最小割模型在信息学竞赛中的应用》)

    闭合图:有向图的点集,集合中的点的出边都指向点集内部的点,$(u,v)in E$则当$u$成立时$v$成立(即:$u$蕴含$v$($u->v$))。

    最大权闭合子图:点权之和最大的闭合图。

    建图:每一条有向边变为容量为inf,源S到正权点v($w_v>0$)的边容量$w_v$,负权点v($w_v<0$)到汇$T$的边容量$-w_v$,零权点v($w_v=0$)不与源和汇相连。然后求最小割(SUM-最大流)即为答案。

    方法:

    最大闭合权子图

    建图:

    S向客户连边(S,i,Ci)
    站向T连边(i,T,Xi)
    客户向站连边(i,j,inf)
    答案为sum-dinic()

     1 void build()
     2 {
     3     dinic.init(n + m + 2);
     4     dinic.st = 0;
     5     dinic.ed = 1;
     6     for (int i = 0; i < n; i++)
     7     {
     8         int x;
     9         scanf("%d", &x);
    10         dinic.adde(i + 2, dinic.ed, x);
    11     }
    12     for (int i = 0 + n + 2; i < m + n + 2; i++)
    13     {
    14         int u, v, w;
    15         scanf("%d%d%d", &u, &v, &w);
    16         sum += w;
    17         dinic.adde(dinic.st, i, w);
    18         dinic.adde(i, u + 1, inf);
    19         dinic.adde(i, v + 1, inf);
    20     }
    21 }

    代码:

      1 /********************************************
      2 *ACM Solutions
      3 *
      4 *@Title: SPOJ PROFIT Maximum Profit
      5 *@Version: 1.0
      6 *@Time: 2014-08-27
      7 *@Solution: http://www.cnblogs.com/xysmlx/p/xxxxxxx.html
      8 *
      9 *@Author: xysmlx(Lingxiao Ma)
     10 *@Blog: http://www.cnblogs.com/xysmlx
     11 *@EMail: xysmlx@163.com
     12 *
     13 *Copyright (C) 2011-2015 xysmlx(Lingxiao Ma)
     14 ********************************************/
     15 // #pragma comment(linker, "/STACK:102400000,102400000")
     16 #include <cstdio>
     17 #include <iostream>
     18 #include <cstring>
     19 #include <string>
     20 #include <cmath>
     21 #include <set>
     22 #include <list>
     23 #include <map>
     24 #include <iterator>
     25 #include <cstdlib>
     26 #include <vector>
     27 #include <queue>
     28 #include <stack>
     29 #include <algorithm>
     30 #include <functional>
     31 using namespace std;
     32 typedef long long LL;
     33 #define pb push_back
     34 #define ROUND(x) round(x)
     35 #define FLOOR(x) floor(x)
     36 #define CEIL(x) ceil(x)
     37 const int maxn = 60010;
     38 const int maxm = 2000010;
     39 const int inf = 0x3f3f3f3f;
     40 const LL inf64 = 0x3f3f3f3f3f3f3f3fLL;
     41 const double INF = 1e30;
     42 const double eps = 1e-6;
     43 const int P[4] = {0, 0, -1, 1};
     44 const int Q[4] = {1, -1, 0, 0};
     45 const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1};
     46 const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1};
     47 
     48 /**
     49 *最大流最小割:加各种优化的Dinic算法($O(V^2E)$)
     50 *输入:图(链式前向星),n(顶点个数,包含源汇),st(源),ed(汇)
     51 *输出:Dinic(NdFlow)(最大流),MinCut()(最小割)(需先求最大流)
     52 *打印路径方法:按反向边(i&1)的flow 找,或者按边的flow找
     53 */
     54 // const int maxn = 0;
     55 // const int maxm = 0;
     56 // const int inf = 0x3f3f3f3f;
     57 struct DINIC
     58 {
     59     struct Edge
     60     {
     61         int u, v;
     62         int cap, flow;
     63         int next;
     64     } edge[maxm];
     65     int head[maxn], en; //需初始化
     66     int n, m, d[maxn], cur[maxn];
     67     int st, ed;
     68     bool vis[maxn];
     69     void init(int _n = 0)
     70     {
     71         n = _n;
     72         memset(head, -1, sizeof(head));
     73         en = 0;
     74     }
     75     void addse(int u, int v, int cap, int flow)
     76     {
     77         edge[en].u = u;
     78         edge[en].v = v;
     79         edge[en].cap = cap;
     80         edge[en].flow = flow;
     81         edge[en].next = head[u];
     82         head[u] = en++;
     83         cur[u] = head[u];
     84     }
     85     void adde(int u, int v, int cap)
     86     {
     87         addse(u, v, cap, 0);
     88         addse(v, u, 0, 0); //注意加反向0 边
     89     }
     90     bool BFS()
     91     {
     92         queue<int> Q;
     93         memset(vis, 0, sizeof(vis));
     94         Q.push(st);
     95         d[st] = 0;
     96         vis[st] = 1;
     97         while (!Q.empty())
     98         {
     99             int u = Q.front();
    100             Q.pop();
    101             for (int i = head[u]; i != -1; i = edge[i].next)
    102             {
    103                 int v = edge[i].v;
    104                 int w = edge[i].cap - edge[i].flow;
    105                 if (w > 0 && !vis[v])
    106                 {
    107                     vis[v] = 1;
    108                     Q.push(v);
    109                     d[v] = d[u] + 1;
    110                     if (v == ed) return 1;
    111                 }
    112             }
    113         }
    114         return false;
    115     }
    116     int Aug(int u, int a)
    117     {
    118         if (u == ed) return a;
    119         int aug = 0, delta;
    120         for (int &i = cur[u]; i != -1; i = edge[i].next)
    121         {
    122             int v = edge[i].v;
    123             int w = edge[i].cap - edge[i].flow;
    124             if (w > 0 && d[v] == d[u] + 1)
    125             {
    126                 delta = Aug(v, min(a, w));
    127                 if (delta)
    128                 {
    129                     edge[i].flow += delta;
    130                     edge[i ^ 1].flow -= delta;
    131                     aug += delta;
    132                     if (!(a -= delta)) break;
    133                 }
    134             }
    135         }
    136         if (!aug) d[u] = -1;
    137         return aug;
    138     }
    139     int Dinic(int NdFlow)
    140     {
    141         int flow = 0;
    142         while (BFS())
    143         {
    144             memcpy(cur, head, sizeof(int) * (n + 1));
    145             flow += Aug(st, inf);
    146             /*如果超过指定流量就return 掉*/
    147             if (NdFlow == inf) continue;
    148             if (flow > NdFlow) break;
    149         }
    150         return flow;
    151     }
    152     /*残余网络*/
    153     void Reduce()
    154     {
    155         for (int i = 0; i < en; i++) edge[i].cap -= edge[i].flow;
    156     }
    157     /*清空流量*/
    158     void ClearFlow()
    159     {
    160         for (int i = 0; i < en; i++) edge[i].flow = 0;
    161     }
    162     /*求最小割*/
    163     vector<int> MinCut()
    164     {
    165         BFS();
    166         vector<int> ans;
    167         for (int u = 0; u < n; u++)
    168         {
    169             if (!vis[u]) continue;
    170             for (int i = head[u]; i != -1; i = edge[i].next)
    171             {
    172                 if (i & 1) continue; /*忽略反向边*/
    173                 int v = edge[i].v;
    174                 int w = edge[i].cap;
    175                 if (!vis[v] && w > 0) ans.push_back(i);
    176             }
    177         }
    178         return ans;
    179     }
    180 } dinic;
    181 
    182 int kase;
    183 int n, m;
    184 int sum;
    185 void init()
    186 {
    187     kase++;
    188     sum = 0;
    189 }
    190 void input()
    191 {
    192     scanf("%d%d", &n, &m);
    193 }
    194 void debug()
    195 {
    196     //
    197 }
    198 void build()
    199 {
    200     dinic.init(n + m + 2);
    201     dinic.st = 0;
    202     dinic.ed = 1;
    203     for (int i = 0; i < n; i++)
    204     {
    205         int x;
    206         scanf("%d", &x);
    207         dinic.adde(i + 2, dinic.ed, x);
    208     }
    209     for (int i = 0 + n + 2; i < m + n + 2; i++)
    210     {
    211         int u, v, w;
    212         scanf("%d%d%d", &u, &v, &w);
    213         sum += w;
    214         dinic.adde(dinic.st, i, w);
    215         dinic.adde(i, u + 1, inf);
    216         dinic.adde(i, v + 1, inf);
    217     }
    218 }
    219 void solve()
    220 {
    221     build();
    222     printf("%d
    ", sum - dinic.Dinic(inf));
    223 }
    224 void output()
    225 {
    226     //
    227 }
    228 int main()
    229 {
    230     // int size = 256 << 20; // 256MB
    231     // char *p = (char *)malloc(size) + size;
    232     // __asm__("movl %0, %%esp
    " :: "r"(p));
    233 
    234     // std::ios_base::sync_with_stdio(false);
    235 #ifdef xysmlx
    236     freopen("in.cpp", "r", stdin);
    237 #endif
    238 
    239     kase = 0;
    240     int T;
    241     scanf("%d", &T);
    242     while (T--)
    243     {
    244         init();
    245         input();
    246         solve();
    247         output();
    248     }
    249     return 0;
    250 }
    SPOJ PROFIT
  • 相关阅读:
    C#---将数据库数据转换为json格式
    ASP.NET ---根据值让树中某一节点选中
    SQL---查询树中某个节点及其所有子节点
    CSS---相对定位笔记
    CSS---绝对定位笔记
    滑雪
    Self Numbers
    Lotto
    Parencodings
    Robot Motion
  • 原文地址:https://www.cnblogs.com/xysmlx/p/3939390.html
Copyright © 2020-2023  润新知