最大密度子图

 

     转载请注明出处: http://www.cnblogs.com/gufeiyang

 

   个人微博:flysea_gu

 

 

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

 

思路: 这道题真心不会。 可以确定的是一道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之间的点就是选择的点的方案。

 

AC代码:

View Code
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <string>
  4 #include <queue>
  5 #include <algorithm>
  6 #include <iostream>
  7 using namespace std;
  8 const int N = 201, M = 10100;
  9 const double INF = 10000000000;
 10 
 11 struct EDGE
 12  {
 13      int u, v, next;
 14      double cap;
 15  }edge[M];
 16 
 17 int map[M][2], n, m, dis[N], cur[N], gap[N], pre[N];
 18 int num, head[N], d[N], step, path[N], s, t;
 19 bool used[N];
 20 
 21 void init()
 22  {
 23      memset(d, 0, sizeof(d));
 24      for (int i=1; i<=m; i++)
 25       {
 26           scanf("%d%d", &map[i][0], &map[i][1]);
 27           d[map[i][0]]++;
 28           d[map[i][1]]++;
 29       }
 30  }
 31 
 32 void add(int u, int v, double w)
 33  {
 34      edge[num].u = u;
 35      edge[num].v = v;
 36      edge[num].cap = w;
 37      edge[num].next = head[u];
 38      head[u] = num++;
 39  }
 40 
 41 double SAP(int s, int t)
 42  {
 43      memset(gap,0,sizeof(gap));
 44      memset(dis,0,sizeof(dis));
 45      int i;
 46      for(int i = 1;i <= t;i++)
 47       cur[i] = head[i];
 48      int top = s;
 49      gap[s] = t;
 50      double maxflow = 0,flow = INF;
 51      while(dis[s] < t)
 52       {
 53           for(i = head[top];i != -1;i = edge[i].next)
 54            {
 55                if(edge[i].cap > 0&& dis[top] == dis[edge[i].v] + 1)
 56                  break;
 57            }
 58           if(i != -1)
 59            {
 60                cur[top] = i;
 61                int v = edge[i].v;
 62                if(edge[i].cap < flow)
 63                 flow = edge[i].cap;
 64                top = v;
 65                pre[v] = i;
 66                if(top == t)
 67                {
 68                    maxflow += flow;
 69                    while(top != s)
 70                     {
 71                         edge[pre[top]].cap -= flow;
 72                         edge[pre[top]^1].cap += flow;
 73                         top = edge[pre[top]^1].v;
 74                     }
 75                     flow = INF;
 76                }
 77            }
 78           else
 79           {
 80             if(--gap[dis[top]] == 0)
 81              break;
 82             dis[top] = t;
 83             cur[top] = head[top];
 84             for(int j = head[top];j != -1;j = edge[j].next)
 85              {
 86                  if(edge[j].cap > 0&& dis[edge[j].v] + 1 < dis[top])
 87                   {
 88                       dis[top] = dis[edge[j].v] + 1;
 89                       cur[top] = j;
 90                   }
 91              }
 92             gap[dis[top]]++;
 93             if(top != s)
 94              {
 95                  top = edge[pre[top]^1].v;
 96              }
 97           }
 98       }
 99     return maxflow;
100  }
101 
102 double makegraph(double g)
103  {
104      num = 0;
105      memset(head, -1, sizeof(head));
106      for(int i=1; i<=n; i++)
107       {
108           add(s, i, m);
109           add(i, s, 0);
110           add(i, t, m+2*g-d[i]);
111           add(t, i, 0);
112       }
113      for(int i=1; i<=m; i++)
114       {
115           add(map[i][0], map[i][1] , 1);
116           add(map[i][1], map[i][0] , 0);
117 
118           add(map[i][1], map[i][0] , 1);
119           add(map[i][0], map[i][1] , 0);
120       }
121      return n*m - SAP(s, t);
122  }
123 
124 void dfs(int u)
125  {
126      used[u] = 1;
127      if(u>=1 && u<=n)
128       path[++step] = u;
129      int v;
130      for(int i=head[u]; i!=-1; i=edge[i].next)
131       {
132           v = edge[i].v;
133           if(edge[i].cap >0 && !used[v])
134            dfs(v);
135       }
136  }
137 
138 void solve()
139  {
140      if(m == 0)
141       {
142           printf("1\n1\n");
143           return ;
144       }
145      double left=0, right=m, mid, esp = 1.0/n/n/2;
146      double now;
147      s = n+1;
148      t = n+2;
149      while(right-left > esp)
150       {
151           mid = (left+right)/2;
152           now = makegraph(mid);
153           if(now > 0)
154            left = mid;
155           else right = mid;
156       }
157      makegraph(left);
158      memset(used, 0, sizeof(used));
159      step = 0;
160      dfs(s);
161      printf("%d\n", step);
162      sort(path+1, path+step+1);
163      for(int i=1; i<=step; i++)
164       printf("%d\n", path[i]);
165  }
166 
167 int main()
168  {
169      while(scanf("%d%d", &n, &m) != EOF)
170      {
171          init();
172          solve();
173      }
174     return 0;
175  }

 

 

posted @ 2012-10-04 18:35  Gu Feiyang  阅读(3825)  评论(0编辑  收藏  举报