最大權閉合子圖-最小割-網絡流

題目鏈接:這裡傳送

  題目大意:給定一個n個數的序列,標號為1~n,有正有負,可以無數次操作:刪去一些數,條件是刪去編號為i的數同時,所有編號是i的整數倍的數都要被刪去。求剩下的數的和最大時的和,即剩下的sum最大。

  解題思路:典型的最大權閉合子圖問題,有關知識的詳細可參考:我覺得最能看懂的博文

  簡要介紹:如果選一個x,就必須要選另一個y,也就是綁定的話,建從x到y的容量為INF的邊,然後從S向所有正值x的點建容量為x的邊,從所有負值x向T建容量為|x|的邊,然後跑從S到T的最小割(最大流),用原序列的所有正值的和sum來減去最小割,得到的就是最大權閉合子圖的權值,也就是結果。

  本題的思想轉化為,如果要保留編號為i個數,就必須保留所有編號為i的因子的數,也就是對第i個數,找出所有存在的編號為i的整數倍k*i的數,建從k*i到i的INF的邊。

以下是AC代碼:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=2e3;
  4 const int INF=0x3f3f3f3f;
  5 int n;
  6 struct Dinic
  7 {
  8     struct Edge
  9     {
 10         int from, to, cap, flow;
 11         Edge(int u, int v, int c, int f)
 12             : from(u), to(v), cap(c), flow(f) {}
 13     };
 14     int n, m, s, t;
 15     vector<Edge> edges;
 16     vector<int> G[N];
 17     bool vis[N];
 18     int d[N];
 19     int cur[N];
 20     void init(int n)
 21     {
 22         this->n = n;
 23         for (int i = 0; i < n; i++) G[i].clear();
 24         edges.clear();
 25     }
 26     void AddEdge(int from, int to, int cap)
 27     {
 28         edges.emplace_back(from, to, cap, 0);
 29         edges.emplace_back(to, from, 0, 0);
 30         m = edges.size();
 31         G[from].push_back(m - 2);
 32         G[to].push_back(m - 1);
 33     }
 34     bool BFS()
 35     {
 36         memset(vis, 0, sizeof(vis));
 37         memset(d, 0, sizeof(d));
 38         queue<int> q;
 39         q.push(s);
 40         d[s] = 0;
 41         vis[s] = 1;
 42         while (!q.empty())
 43         {
 44             int x = q.front();
 45             q.pop();
 46             for (int i = 0; i < G[x].size(); i++)
 47             {
 48                 Edge& e = edges[G[x][i]];
 49                 if (!vis[e.to] && e.cap > e.flow)
 50                 {
 51                     vis[e.to] = 1;
 52                     d[e.to] = d[x] + 1;
 53                     q.push(e.to);
 54                 }
 55             }
 56         }
 57         return vis[t];
 58     }
 59     int DFS(int x, int a)
 60     {
 61         if (x == t || a == 0) return a;
 62         int flow = 0, f;
 63         for (int& i = cur[x]; i < G[x].size(); i++)
 64         {
 65             Edge& e = edges[G[x][i]];
 66             if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
 67             {
 68                 e.flow += f;
 69                 edges[G[x][i] ^ 1].flow -= f;
 70                 flow += f;
 71                 a -= f;
 72                 if (a == 0) break;
 73             }
 74         }
 75         return flow;
 76     }
 77     int Maxflow(int s, int t)
 78     {
 79         this->s = s, this->t = t;
 80         int flow = 0;
 81         while (BFS())
 82         {
 83             memset(cur, 0, sizeof(cur));
 84             flow += DFS(s, INF);
 85         }
 86         return flow;
 87     }
 88 } solver;
 89
 90 int main()
 91 {
 92     scanf("%d",&n);
 93     solver.init(n+3);
 94     int s=0,t=n+1,x,sum=0;
 95     for(int i=1;i<=n;++i)
 96     {
 97         scanf("%d",&x);
 98         if(x<0)
 99             solver.AddEdge(i,t,-x);
100         else
101         {
102             solver.AddEdge(s,i,x);
103             sum+=x;
104         }
105         for(int j=2;i*j<=n;++j)
106             solver.AddEdge(i*j,i,INF);
107     }
108     printf("%d\n",sum-solver.Maxflow(s,t));
109 }

原文地址:https://www.cnblogs.com/Lin88/p/10015583.html

时间: 2024-07-30 03:19:52

最大權閉合子圖-最小割-網絡流的相关文章

noi 2006 最大收益 最大权闭合图转最小割转最大流

题意:一个公司有n个可以建造通讯战的地方,建造成本分别为pi,然后第i个公司会选择使用通讯站ai与bi,使用费用是ci,然后问这个通讯公司怎么建站能够获利最大.(净获利=总收益-总成本): 网上看到一篇题解,直接说这是个最小割,求最小割然后总收益-最小割就是了.这种题解就是一点用也没有,为什么是最小割,总得解释解释吧,撂下结论就跑了,这种题解写来何用. 之后查了一篇国家集训队的论文<最小割模型在信息学竞赛中的应用>才明白原来是最大权闭合图转的最小割,至于为什么能转成最小割,自己去看论文的证明吧

HDU 1565 &amp;&amp; HDU 1569 方格取数 (网络流之最小割)

题目地址:HDU 1565       HDU 1569 刚开始接触最小割,就已经感受到了最小割的博大精深... 这建图思路倒是好想..因为好多这种关于不相邻的这种网络流都是基本都是这样建图.但是感觉毫无道理可言...看了题解后才明白这样做的意义. 下面是题解中的说法. 大概是这样分析的,题义是要我们求在一个方格内取出N个点,使得这N个独立的(不相邻)点集的和最大.我们可以将问题转化为最小割来求解.首先,我们将方格进行黑白相间的染色,然后再将任意一种颜色(黑色)作为源点,一种颜色(白色)作为汇点

猴子课堂:最大流与最小割

注:本人只是一个萌新,有一些地方的用语会不太专业(大佬:是十分不专业),我不会用什么技术用语,这些文章对那些跟我一样的萌新会比较适用! 最大流: 原题地址 最大流我讲的是我自己对dinic算法的一些思想,希望对你会有用! 我记网络流靠三个关键字: 1.找最短路径 将流量流向终点,且损害最少的边,这是找路径的一个关键,那么,便可以把分出最少的层面,以便后面的查找! 如图: ? 分层 ? 分层可以用宽搜(宽搜可以保证层数最少),用h数组储存层,具体如下代码: int list[21000],head

【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1685  Solved: 724[Submit][Status][Discuss] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案

POJ 3308 Paratroopers (二分图最小点权覆盖 -&gt; 最小割 -&gt; 最大流)

POJ 3308 Paratroopers 链接:http://poj.org/problem?id=3308 题意:有一个N*M的方阵,有L个伞兵降落在方阵上.现在要将所有的伞兵都消灭掉,可以在每行每列装一个高射炮,如果在某行(某列)装上高射炮之后,能够消灭所有落在该行(该列)的伞兵.每行每列安高射炮有费用,问如何安装能够使得费用之积最小. 思路:首先题目要求乘积最小,将乘积对e取对数,会发现就变成了求和.然后抽象出一个二分图,每一行是x部的一个点,每个点有权值,权值为费用取ln.每一列是y部

Harry Potter and the Forbidden Forest(割边最小的最小割)

Harry Potter and the Forbidden Forest Time Limit:3000MS    Memory Limit:65536KB    64bit IO Format:%I64d & %I64u Description Harry Potter notices some Death Eaters try to slip into Castle. The Death Eaters hide in the most depths of Forbidden Forest.

hdu4289(最小割)

传送门:Control 题意:有n个城市,有个小偷想从其中一个城市逃到另一个城市,警察想要堵截这个小偷,知道了在每个城市堵截的成本,问如何安排在哪些城市堵截可以使得小偷一定会被抓住,而且成本最低. 分析:根据割的定义将整部图分成两部分且互不相通,这题明显是求最小割,根据最小割等于最大流,则拆点后直接求最大流即可,对于点值在最大流中的限制经常是拆点处理. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <

zoj 3792 Romantic Value(最小割下边数最小)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5300 大致题意:给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少.求出一个比值:剩余边数权值和/删除的边数. 思路:删除边的权值之和最小显然是求最小割即最大流.但同时要求删除边数最少,解决方法是把边数也加到权值上去,一起求最大流,因为边数最多是1000,即每条边的边权置为 w*10000+1,1代表这一条边.

【BZOJ1497】[NOI2006]最大获利 最小割

裸的最小割,很经典的模型. 建图:要求总收益-总成本最大,那么将每条弧与源点相连,流量为成本,每个收益与汇点相连,流量为收益,然后每条弧与它所能到达的收益相连,流量为inf. 与源点相连的是未被选中的弧(未花费的成本),与汇点相连的是选中的收益,那么,初始状态是完美的,显然不可能,因为获得收益必然要花费成本,所以每条源汇点相连的路中必须去掉一条,那么最小割就是最小的(选中的成本和未选的收益的和),每条增广路都是一种抵消,用总收益减去就是最终的选中收益和. 而最小割就是最大流.证明看论文= =.