最大密度子圖


 

     轉載請注明出處: 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  }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM