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