您的位置:首页 > 其它

【01分数规划】最大密度子图

2014-11-29 07:35 405 查看
http://www.cnblogs.com/gufeiyang/archive/2012/10/04/2711618.html

题意:给出一个无向图, 求这个无向图的最大密度子图。  就是选择一个子图,使边的数目比上点的数目最大,并且输出方案。

 

思路: 这道题真心不会。 可以确定的是一道01规划的问题。我们依旧是二分答案g。然后就是按照网上其他人的建图方案做的。

“采用0-1整数规划的思想来求最优解。使用二分查找的方法来求g(h), 初始left = 0, right = m。对于每一个g=(left+right)/2可以建立一个新图。在新图中源点与原图中每一个点连一条容量为m的边。原图中每一条边与汇点连一条容量为m+2*g-dv的边。dv为点v的度数。再将原图中的无向边拆成两条有向边,容量都设为1.然后对此图求最大流(maxflow)。最后将(n*m-maxflow)/2
与0比较大小,如果它大于0,则left=g,否则right = g。” 

最后从s出发搜索(如果有流量往前搜),能搜到的标号在1到n之间的点就是选择的点的方案。

#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 201, M = 10100;
const double INF = 10000000000;

struct EDGE
{
int u, v, next;
double cap;
}edge[M];

int map[M][2], n, m, dis
, cur
, gap
, pre
;
int num, head
, d
, step, path
, s, t;
bool used
;

void init()
{
memset(d, 0, sizeof(d));
for (int i=1; i<=m; i++)
{
scanf("%d%d", &map[i][0], &map[i][1]);
d[map[i][0]]++;
d[map[i][1]]++;
}
}

void add(int u, int v, double w)
{
edge[num].u = u;
edge[num].v = v;
edge[num].cap = w;
edge[num].next = head[u];
head[u] = num++;
}

double SAP(int s, int t)
{
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
int i;
for(int i = 1;i <= t;i++)
cur[i] = head[i];
int top = s;
gap[s] = t;
double maxflow = 0,flow = INF;
while(dis[s] < t)
{
for(i = head[top];i != -1;i = edge[i].next)
{
if(edge[i].cap > 0&& dis[top] == dis[edge[i].v] + 1)
break;
}
if(i != -1)
{
cur[top] = i;
int v = edge[i].v;
if(edge[i].cap < flow)
flow = edge[i].cap;
top = v;
pre[v] = i;
if(top == t)
{
maxflow += flow;
while(top != s)
{
edge[pre[top]].cap -= flow;
edge[pre[top]^1].cap += flow;
top = edge[pre[top]^1].v;
}
flow = INF;
}
}
else
{
if(--gap[dis[top]] == 0)
break;
dis[top] = t;
cur[top] = head[top];
for(int j = head[top];j != -1;j = edge[j].next)
{
if(edge[j].cap > 0&& dis[edge[j].v] + 1 < dis[top])
{
dis[top] = dis[edge[j].v] + 1;
cur[top] = j;
}
}
gap[dis[top]]++;
if(top != s)
{
top = edge[pre[top]^1].v;
}
}
}
return maxflow;
}

double makegraph(double g)
{
num = 0;
memset(head, -1, sizeof(head));
for(int i=1; i<=n; i++)
{
add(s, i, m);
add(i, s, 0);
add(i, t, m+2*g-d[i]);
add(t, i, 0);
}
for(int i=1; i<=m; i++)
{
add(map[i][0], map[i][1] , 1);
add(map[i][1], map[i][0] , 0);

add(map[i][1], map[i][0] , 1);
add(map[i][0], map[i][1] , 0);
}
return n*m - SAP(s, t);
}

void dfs(int u)
{
used[u] = 1;
if(u>=1 && u<=n)
path[++step] = u;
int v;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
v = edge[i].v;
if(edge[i].cap >0 && !used[v])
dfs(v);
}
}

void solve()
{
if(m == 0)
{
printf("1\n1\n");
return ;
}
double left=0, right=m, mid, esp = 1.0/n/n/2;
double now;
s = n+1;
t = n+2;
while(right-left > esp)
{
mid = (left+right)/2;
now = makegraph(mid);
if(now > 0)
left = mid;
else right = mid;
}
makegraph(left);
memset(used, 0, sizeof(used));
step = 0;
dfs(s);
printf("%d\n", step);
sort(path+1, path+step+1);
for(int i=1; i<=step; i++)
printf("%d\n", path[i]);
}

int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
init();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: