zoj 2676 Network Wars 最小割+0-1分数规划

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676

题意:

给出N个点和M条边,要求一个割集,使得集合中 ans = 所有边点权值和/边的数量 最小。

思路:

0-1分数规划。

具体证明参考 胡伯涛 《最小割模型在信息学竞赛中的应用》

设g = min(Σwi/Σ1)

转化为 求g使得 (Σwi - g*Σ1) = 0。

所以二分求g的值。

每次建图的时候,以1为源点,N为汇点。

原来图中每条边的容量 = wi-g。

要注意点是如果容量<0,那么这条边必在割集中。

如果容量>=0,在图中连起来然后求最小割。

最后输出边集。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <string>
  4 #include <cstdio>
  5 #include <queue>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <vector>
  9 using namespace std;
 10 #define maxn 105
 11 const double inf = 10000007;
 12 const double eps = 1e-8;
 13 struct Edge
 14 {
 15     int from, to, xh;
 16     double cap, flow;
 17     Edge(int f, int t, double c, double fl, int x)
 18     {
 19         from = f; to = t; cap = c; flow = fl; xh = x;
 20     }
 21 };
 22 struct Edge2
 23 {
 24     int from, to;
 25     double cost;
 26 }init[405];
 27 vector <Edge> edges;
 28 vector <int> G[maxn];
 29 int n, m, s, t;
 30 int vis[maxn], cur[maxn], d[maxn];
 31 double min(double a, double b)
 32 {
 33     return a<b?a:b;
 34 }
 35 void AddEdge(int from, int to, double cap, int xh)
 36 {
 37     edges.push_back(Edge(from, to, cap, 0, xh));
 38     edges.push_back(Edge(to, from, 0, 0, -1));
 39     m = edges.size();
 40     G[from].push_back(m-2);
 41     G[to].push_back(m-1);
 42 }
 43 bool bfs()
 44 {
 45     memset(vis, 0, sizeof(vis));
 46     d[s] = 0;
 47     vis[s] = 1;
 48     queue <int> q;
 49     q.push(s);
 50     while(!q.empty())
 51     {
 52         int u = q.front(); q.pop();
 53         for(int i = 0; i < G[u].size(); i++)
 54         {
 55             Edge &e = edges[G[u][i]];
 56             if(!vis[e.to] && e.cap-e.flow > eps)
 57             {
 58                 vis[e.to] = 1;
 59                 d[e.to] = d[u]+1;
 60                 q.push(e.to);
 61             }
 62         }
 63     }
 64     return vis[t];
 65 }
 66 double dfs(int x, double a)
 67 {
 68     if(x == t || fabs(a) <eps) return a;
 69     double flow = 0, f;
 70     for(int &i = cur[x]; i < G[x].size(); i++)
 71     {
 72         Edge &e = edges[G[x][i]];
 73         if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > eps)
 74         {
 75             e.flow += f;
 76             edges[G[x][i]^1].flow -= f;
 77             flow += f;
 78             a -= f;
 79             if(fabs(a) < eps) break;
 80         }
 81     }
 82     return flow;
 83 }
 84 double Maxflow()
 85 {
 86     double flow = 0;
 87     while(bfs())
 88     {
 89         memset(cur, 0, sizeof(cur));
 90         flow += dfs(s, inf);
 91     }
 92     return flow;
 93 }
 94 int N, M;
 95 int main()
 96 {
 97     while(~scanf("%d%d", &N, &M))
 98     {
 99         for(int i = 1; i <= M; i++)
100         {
101             scanf("%d%d%lf", &init[i].from, &init[i].to, &init[i].cost);
102         }
103         double l = 0, r = 10000001;
104         s = 1, t = N; n = N;
105         double mid;
106         double sum = 0;
107         while(l+eps <= r)
108         {
109             edges.clear();
110             for(int i = 1; i <= N; i++) G[i].clear();
111             mid = (l+r)/2.0;
112             sum = 0;
113             for(int i = 1; i <= M; i++)
114             {
115                 double temp = init[i].cost - mid;
116                 if(temp < 0) sum += temp;
117                 else
118                 {
119                     AddEdge(init[i].from, init[i].to, temp, i);
120                     AddEdge(init[i].to, init[i].from, temp, i);
121                 }
122             }
123             sum += Maxflow();
124             if(sum >= eps) l = mid;
125             else r = mid;
126         }
127         vector <int> ans;
128         edges.clear();
129         for(int i = 1; i <= N; i++) G[i].clear();
130         for(int i = 1; i <= M; i++)
131         {
132             double temp = init[i].cost - mid;
133             if(temp >= 0)
134             {
135                 AddEdge(init[i].from, init[i].to, temp, i);
136                 AddEdge(init[i].to, init[i].from, temp, i);
137             }
138         }
139         Maxflow();
140         int cnt = 0;
141         for(int i = 1; i <= M; i++)
142         {
143             if((vis[init[i].from] + vis[init[i].to]) == 1 || init[i].cost + eps < mid)
144             {
145                 cnt++;
146             }
147         }
148         printf("%d\n", cnt);
149         bool flag = true;
150         for(int i = 1; i <= M; i++)
151         {
152             if((vis[init[i].from] + vis[init[i].to]) == 1 || init[i].cost + eps < mid)
153             {
154                 if(flag)
155                 {
156                     printf("%d", i);
157                     flag = false;
158                 }
159                 else printf(" %d", i);
160             }
161         }
162         printf("\n");
163
164     }
165
166     return 0;
167 }
时间: 2024-11-03 21:00:45

zoj 2676 Network Wars 最小割+0-1分数规划的相关文章

zoj 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

ZOJ 2676 Network Wars[01分数规划]

ZOJ Problem Set - 2676 Network Wars Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge Network of Byteland consists of n servers, connected by m optical cables. Each cable connects two servers and can transmit data in both direction

ZOJ 2676 Network Wars(最优比例最小割)

Network Wars Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge Network of Byteland consists of n servers, connected by m optical cables. Each cable connects two servers and can transmit data in both directions. Two servers of the n

2019.4.9 一题——概率期望+0/1分数规划+最大权闭合子图

没注意 “第 x 条边和第 y 条边的起点是相同的” 的限制.没想出来. 有这个限制,可以考虑每个点分别计算.令 \( f[i] \) 表示从 i 出发的最大边数期望,那么先把拓扑序在自己之后的点的 \( f[ ] \) 算出来,然后考虑自己这个点的出边怎么做能使自己的 \( f[ ] \) 最大. \( f[i]=\frac{ \sum f[j]+1 }{ d } \) ,其中 d 是保留下来的边数, j 是保留边指向的点. 如果把 \( f[ ]+1 \) 看做收益, 1 看做代价,那么这个

POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)

用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ 前提是在TLE了好几次下过的 = = 题目意思:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小,很显然,这个题目是要求一棵最优比率生成树. 解题思路: 对答案进行二分,当把代进去的答案拿来算最小生成树的时候,一旦总路径长度为0,就是需要的答案. 0-1规划是啥? 概念有带权图G, 对于图中每条

bzoj 3232 圈地游戏——0/1分数规划(或网络流)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3232 当然是0/1分数规划.但加的东西和减的东西不在一起,怎么办? 考虑把它们合在一起.因为边围成的形状像一个环,所以把格子的贡献也放到边上,然后正常判环. 放到边上的方法就是:比如竖着的边,可以在每一行上维护该行格子值前缀和,然后指定那个围成的形状是,比如,逆时针的,那么向上的边就加上到它为止的前缀值,向下的边就减去到它为止的前缀值,然后就能判环了! 这样一定只有一个环.但多个环答案不会

0/1分数规划

学习了lyd书上的0/1分数规划,发现这类题目都有一个特点,就是求$\frac{\sum_{a_{i}*x_{i}}}{\sum_{b_{i}*x_{i}}}$的最大或者最小,再加一些限制取不取的条件. POJ2976 二分答案+sort取前(n-k+1)个. #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; con

『0/1分数规划 二分法』

0/1分数规划 模型 0/1分数规划指的是这样一个问题模型: 给定整数\(a_1,a_2,...,a_n\)和\(b_1,b_2,...,b_n\),求一组解\(x_1,x_2,...,x_n(\forall\ i\in[1,n],x_i=1,0)\),使得下式最大化:\[\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}\] 简单地说,就是给定\(n\)对整数\(a_i,b_i\),从中选取若干对,使得选出的\(a\)之和与\(b\)之和的比值最大.

[例题/总结]0/1分数规划

[TOC] ##一.总述 0/1分数规划是专门解决0/1分数规划模型的一种算法~~(废话)~~.所以说0/1分数规划模型是什么呢?给定整数{\(a_1,a_2,a_3,...,a_n\)},{\(b_1,b_2,b_3,...,b_n\)}从中选出若干对数,使得它们各自和的比值最大.公式如下: \(\frac{\sum_{p=1}^{n}a_p\times x_p}{\sum_{p=1}^{n}b_p\times x_p}(x_p=1,0)\) ##二.实现原理 那么我们用什么方法可以求出这样一