POJ Hard Life (最大密度子图)

                                Hard Life

 

做该题前需要先了解一些专有名词及定理。

希望你可以亲自看看2007年胡伯涛的论文!

有向图的闭合图(closure): 闭合图内任意点的任意后继也一定还在闭合图中。

 

题目:

   给出N个人,有些人之间有联系,而有联系的两个人被认为是一个整体。如果,把人看作点,把关系看作边,则要求你求出 边 / 点 的比值最大。而这些点边之间必须是一个闭合图。

 

算法分析:

最大密度子图算法构造:

 

把原图中的无向边转换成两条有向边,容量为1

设一源点,连接所有点,容量为U(取m)。

设一汇点,所有点连接汇点,容量为 U+2g-dv 

二分枚举最大密度g,其中dvv的度。

判断(U*n-MaxFlow)/2.>=0

最后跳出的L就是最大密度。

拿这个L再重新建图,求最大流。

然后从s出发bfs或者dfs,走残留容量大于0的边,所有能到达的点就是答案。

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
using namespace std;

typedef pair<int,int> pii;
const double INF = 1e7;
const double EPS = 1e-7;
const int MAXN = 100 + 10;
struct Edge{
   int from,to;
   double cap,flow;
   Edge(){};
   Edge(int _from,int _to,double _cap,double _flow)
       :from(_from),to(_to),cap(_cap),flow(_flow){};
};

pii verter[1010];
vector<Edge> edges;
vector<int> G[MAXN];
int d[MAXN],cur[MAXN];
bool vst[MAXN];
int dv[MAXN];
int V,E,S,T;
int num;

void clr(){
   for(int i = 0;i <= T;++i)
      G[i].clear();
   edges.clear();
}

void addEdge(int f,int t,double w){
   edges.push_back(Edge(f,t,w,0.0));
   edges.push_back(Edge(t,f,0.0,0.0));
   int sz = edges.size();
   G[f].push_back(sz - 2);
   G[t].push_back(sz - 1);
}

bool BFS(){
   memset(vst,0,sizeof(vst));
   queue<int> Q;
   Q.push(S);
   d[S] = 0;
   vst[S] = 1;
   while(!Q.empty()){
       int x = Q.front(); Q.pop();
       for(int i = 0;i < (int)G[x].size();++i){
           Edge& e = edges[G[x][i]];
           if(!vst[e.to] && e.cap > e.flow){
              vst[e.to] = 1;
              d[e.to] = d[x] + 1;
              Q.push(e.to);
           }
       }
   }
   return vst[T];
}

double DFS(int x,double a){
   if(x == T||a == 0) return a;

   double flow = 0,f;
   for(int& i = cur[x];i < (int)G[x].size();++i){
       Edge& e = edges[G[x][i]];
       if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap - e.flow))) > 0){
           e.flow += f;
           edges[G[x][i]^1].flow -= f;
           flow += f;
           a -= f;
           if(a == 0) break;
       }
   }
   return flow;
}

double maxFlow(){
  double flow = 0;
  while(BFS()){
     memset(cur,0,sizeof(cur));
     flow += DFS(S,INF);
  }
  return flow;
}

void build(double g){
    clr();
    for(int i = 0;i < E;++i){
        addEdge(verter[i].first,verter[i].second,1.0);
        addEdge(verter[i].second,verter[i].first,1.0);
    }

    for(int i = 1;i <= V;++i){
        addEdge(S,i,E*1.0);
        addEdge(i,T,(1.0*E + 2.0 * g - dv[i]));
    }
}

//查找割边
void dfs(int u){
   vst[u] = 1;
   if(u <= V) num++;
   for(int i = 0;i < (int)G[u].size();++i){
       Edge& e = edges[G[u][i]];
       if(!vst[e.to] && e.cap > e.flow){
          dfs(e.to);
       }
   }
}

void solve(){
   double c,lb = 0,ub = E*1.0;
   for(int k = 0;k < 100;++k){
      double mid = (lb + ub) / 2.0;

      build(mid);
      c = maxFlow();
      c = (E * V * 1.0 - c) / 2.0;


      if(c > EPS){
         lb = mid;
      } else {
         ub = mid;
      }
   }

   build(lb);
   maxFlow();
   memset(vst,0,sizeof(vst));
   num = 0;
   dfs(S);

   printf("%d\n",num);
   for(int i = 1;i <= V;++i){
      if(vst[i]) printf("%d\n",i);
   }

}

int main()
{
//    freopen("Input.txt","r",stdin);
//    freopen("Output.txt","w",stdout);

    while(~scanf("%d%d",&V,&E)){
        int a,b;

        if(E == 0){
            printf("1\n1\n");
            continue;
        }

        S = V + 1; T = V + 2;
        memset(dv,0,sizeof(dv));
        for(int i = 0;i < E;++i){
            scanf("%d%d",&a,&b);
            verter[i] = make_pair(a,b);
            dv[a]++;
            dv[b]++;
        }

        solve();
    }
    return 0;
}


 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值