最近复习网络流,就把这篇文章拿出来好好学习了一下,真是受益匪浅。(虽然学习了好几天了。
一: 增广路方法的复杂度是通过估计增广次数的上界得到的。对于实际应用中的网络,增广次数往往很少,所以使用范围还是很广的,实用性强。(只会Dinic。
二:分数规划。
首先,我们可以了解到它的一般形式。
然后,根据这个单调性,我们可以进行二分。
然后根据Dinkelbach定理
所以,我们就可以二分λ的值,进行求解。
例如
POJ 3111 0/1分数规划
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"
#include"algorithm"
#include"cmath"
using namespace std;
struct g{
int w, v, id;
double value;
}a[100500];
bool cmp(g A, g B)
{
return A.value > B.value;
}
int k, n;
bool check(double x)
{
for(int i = 1; i <= n; i ++){
a[i].value = a[i].v - x * a[i].w;
}
sort(a + 1, a + 1 + n, cmp);
double ans = 0;
for(int i = 1; i <= k; i ++){
ans += a[i].value;
}
if(fabs(ans) < 1e-8) return 1;
if(ans > 0) return 1;
else return 0;
}
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++){
scanf("%d%d", &a[i].v, &a[i].w);
a[i].id = i;
}
double l = 0.0, r = 10000000.0;
for(int i = 1; i <= 50; i ++){
double mid = (l + r) / 2.0;
if(check(mid)){
l = mid;
}
else{
r = mid;
}
}
for(int i = 1; i <= k; i ++){
printf("%d%c", a[i].id, i == k ? '\n' : ' ');
}
return 0;
}
对于每一位进行一个网络流(真是厉害呀。。
三:最大权闭合图
建图
答案
四:最大密度子图
最大密度子图也是一个0/1分数规划问题,问题就在于求出g(λ)的过程。
首先,根据两个不同子图的密度之差,我们可以求出,二分的次数是logn的。
4.1 初步算法 (利用最大闭合权图
4.2 改进算法(推的很棒呀! 但是我好菜呀 有个地方觉得又问题。
首先,我们求的是最大密度子图,那我们在选定一系列点的时候,我们肯定想尽可能多的去选所有与这些点相连的边。但是这一部分的边有的连向的是其他的部分(点集的补集中的点),所有,我们要减去这一部分的边,而这一部分的边就可以转化为两个部分的割。所有点所连的边我们可以用度来统计。所以,我们就可以得到以下结论。
(这个地方有个问题,对于子图,边数 = (度的总和 - 割) / 2, 而公式写成了边数 = 度的总和 / 2 - 割, 这个地方看了很久。还是觉得有问题。然而,却用这个继续推得了要求的流量,最后证明正确性的时候又很完美的证明了。所以,看的一脸懵逼)
(好像看懂了,大概就是一个1:2的系数,后面割的系数没有什么影响)
建图:
答案的推导:
4.3 向带边权图的推广
4.4 向点边都带权的推广
5. 二分图的最小点权覆盖集与最大点权独立集