zoukankan      html  css  js  c++  java
  • poj3155 Hard Life

    题目大意:给一个无向图,求此图的最大密度子图

    输入:n,m,表示有n个点(1 -- n编号),接m行,每行u v,表示u到v有一条无向边。

    网上各种传说这是一种分数规划的东西,然后我也不了解,搜了很多资料,也没有人给了很好的解释。貌似胡伯涛的一篇文章里提到了这样的算法,但是里面的证明各种看不懂。好吧,看不懂我就只有另寻他法了。

     乍一看,毫无策略。方案核心是要找答案,那就直接枚举答案测试好了。题目要找最大密度**,也即(选中的边数/与这些边边有关的点数)。那就二分枚举这个最大密度吧!!!

    假设答案是k,任意所选边集为E,与E对应的点集V,即有max{|E|/|V|} == k,也就是说|E|/|V| <= k 也等价于 |E|-|V|*k <= 0。

    现在测试x是不是答案,若x>k,则不管怎么选都会有 |E|-|V|*k < 0; 若 x < k 则 能找到E使得 |E|-|V|*k > 0。

    现在我们枚举要选中的边,假设选中边uv,那么必选点u、v。若H(x)=E(x)-V(x)*k,选中边uv的结果是H(x)=H(x)+1,选中点u、v的结果是H(x)=H(x)-1-1。

    由于所有边都最终指向两个点,而点是截止的,这不就是最大权闭合子图吗???!!!

    构图是不是就很水了: C(S,UV)=1, C(UV,V)=1, C(UV,U)=1, C(U,T)=x。然后最大流求出,H(x)=m-maxF();

    注意一个小小的坑,用最大流求最大权闭合子图时,H(x) < 0是体现不出来的。所以祝你好运了。贴个代码……

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <queue>
      5 using namespace std;
      6 #define maxn 150
      7 const int maxe = 1001000;
      8 const double maxf = 1e10;
      9 #define zero 1e-8
     10 struct edge{
     11     int u,v; double c;
     12     edge(int e1=0,int e2=0,double e3=0){ u=e1,v=e2; c=e3; }
     13 }e[maxe];
     14 int ec;
     15 int head[maxn];
     16 int next[maxe];
     17 void addedge(int u,int v,double c){
     18     e[ec]=edge(u,v,c);
     19     next[ec]=head[u]; head[u]=ec++;
     20     e[ec]=edge(v,u,0);
     21     next[ec]=head[v]; head[v]=ec++;
     22 }
     23 //***********************************//
     24 int source,sink,maxdep;
     25 int dep[maxn],gap[maxn];
     26 void setGD(){
     27      for(int i=0;i<=maxdep;i++) dep[i] = maxdep; dep[sink] = 0;
     28      int u,v;
     29      queue<int> que;
     30      que.push(sink);
     31      while(!que.empty()){
     32            u = que.front(); que.pop();
     33            for(int i=head[u];i!=-1;i=next[i]){
     34                  v = e[i].v; //if(v > maxdep) continue;
     35                  if(dep[v] < maxdep) continue; //'被访问过'
     36                  dep[v] = dep[u]+1;
     37                  que.push(v);
     38            }
     39      }
     40      memset(gap,0,sizeof(gap));
     41      for(int i=0;i<=maxdep;i++) gap[dep[i]]++;
     42 }
     43 double maxF(){
     44     setGD();
     45     int u=source,i;
     46     int cur[maxn],trace[maxn],top=0;
     47     for(int i=0;i<=maxdep;i++) cur[i] = head[i];
     48     double flow=0;
     49     while(dep[source] <= maxdep){
     50         if(u == sink){
     51              double tf = maxf; int ins;
     52              for(i=0;i<top;i++) //找瓶颈边
     53                 if(tf - e[trace[i]].c > 0)
     54                       tf = e[trace[i]].c, ins = i;
     55              for(i=0;i<top;i++){
     56                 e[trace[i]].c -= tf;
     57                 e[trace[i]^1].c += tf;
     58              }
     59              flow += tf;
     60              u = e[trace[ins]].u, top = ins;
     61         }
     62         if(u != sink && gap[dep[u]-1]==0) break;
     63         for(i=cur[u];i!=-1;i=next[i])
     64              if(e[i].c > zero && dep[u] == dep[e[i].v] + 1)
     65                        break;
     66         if(i != -1) {
     67              trace[top++] = i;
     68              cur[u] = i;
     69              u = e[i].v;
     70         }
     71         else {
     72              int mindep = maxdep;
     73              for(i=head[u];i!=-1;i=next[i]){
     74                  if(e[i].c > zero && dep[e[i].v] < mindep)
     75                            mindep = dep[e[i].v], cur[u] = i;
     76              }
     77              gap[dep[u]]--;
     78              dep[u] =  mindep + 1;
     79              gap[dep[u]]++;
     80              if(u != source)
     81                 u = e[trace[--top]].u;
     82         }
     83     }
     84     return flow;
     85 }
     86 //**********************************//
     87 void initial(){
     88      ec = 0;
     89      memset(head,-1,sizeof(head));
     90      //initial source ,sink and maxdep;
     91 }
     92 int uu[1010],vv[1010],degree[maxn];
     93 double most;
     94 void mapping(int n,int m,double k){
     95     initial();
     96     for(int i=1;i<=n;i++) {
     97         addedge(source,i,most);
     98         addedge(i,sink,most+2*k-degree[i]);
     99     }
    100     for(int i=1;i<=m;i++) {
    101         addedge(vv[i],uu[i],1);
    102         addedge(uu[i],vv[i],1);
    103     }
    104 }
    105 bool visited[maxn];
    106 void search(int u){
    107     visited[u]=1;
    108     for(int i=head[u];i>=0;i=next[i])
    109     if(e[i].c > zero && !visited[e[i].v])
    110         search(e[i].v);
    111 }
    112 int main()
    113 {
    114     int n,m;
    115     while(scanf("%d%d",&n,&m) != EOF){
    116         memset(degree,0,sizeof(degree));
    117         for(int i=1;i<=m;i++)
    118             scanf("%d%d",&uu[i],&vv[i]), degree[uu[i]]++, degree[vv[i]]++;
    119         if(m == 0){
    120             printf("1
    1
    ");
    121             continue;
    122         }
    123         source=0;
    124         sink=n+1;
    125         maxdep=sink+1;
    126         most=m+n;
    127         double left=0,right=m+n,eps=1e-5,mid;
    128         while(right-left > eps){
    129             mid = (left+right)*0.5;
    130             mapping(n,m,mid);
    131             double hx=(n*most-maxF())*0.5;
    132             if(hx>1e-5) left=mid;
    133             else right=mid;
    134         }
    135         mid = left; //mid重新赋值,否则有可能WA掉
    136         mapping(n,m,mid);
    137         double flow=maxF();
    138         //printf("mid = %.10f
    ",mid);
    139         memset(visited,0,sizeof(visited));
    140         search(source);
    141         int ret=0;
    142         for(int i=1;i<=n;i++)
    143         if(visited[i]) ret++;
    144         printf("%d
    ",ret);
    145         for(int i=1;i<=n;i++)
    146         if(visited[i])
    147             printf("%d
    ",i);
    148     }
    149     return 0;
    150 }
    View Code
  • 相关阅读:
    oracle中函数和存储过程的区别和联系
    oracle系统函数(日期函数)
    触发器
    初次使用集合
    框架结构中同时改变多个框架内容,并显示两个页面
    借贷记账法的原理
    IIS7对json支持
    SqlHelper和数据访问层
    在easyui datagrid中formatter数据后使用linkbutton
    jQuery 添加/移除CSS类
  • 原文地址:https://www.cnblogs.com/karlvin/p/3243959.html
Copyright © 2011-2022 走看看