转载请注明出处: 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代码:

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 }