最大密度子图
(话说看到这个名字完全想不到网络流...)
用上了之前的最大权闭合图
然后这个密度的表达式容易想到分数规划
所以...
(1) 初始思路:
直接二分答案g 然后造一个二分图
二分的范围显然是0~m(其实是1/(n*n)~m 整个eps就行)
左部图中的点向右部图中的边连边
然后点连源点(g),边连汇点(1) 跑最大权闭合
其实这个初始思路就很优秀了
但是
--By 《最小割模型在信息学竞赛中的应用》 Amber
(网络流想不出来总可以试试最小割)
点权挂着个g不好缩 我们缩一下边权
考虑选择每个点的花费 就是(g-du[i] / 2)
但是这样有一个负数的问题所以统一加上一个m然后减去 同理可以*2 再除掉
整理一下:
(2) 最终建图
1.每个点向源点连边(m) 汇点连边(m+2g-du[i])
2.原图中的边边权为1
3.最终的最小割是(m*n-maxflow)/2 (简算修正)
这题注意最后求答案之前建个答案的图 因为二分会乱
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<iostream> 5 #include<algorithm> 6 #define ms(a,b) memset(a,b,sizeof a) 7 #define rep(i,a,n) for(int i = a;i <= n;i++) 8 #define per(i,n,a) for(int i = n;i >= a;i--) 9 #define inf 2147483647 10 using namespace std; 11 typedef long long ll; 12 ll read() { 13 ll as = 0,fu = 1; 14 char c = getchar(); 15 while(c < '0' || c > '9') { 16 if(c == '-') fu = -1; 17 c = getchar(); 18 } 19 while(c >= '0' && c <= '9') { 20 as = as * 10 + c - '0'; 21 c = getchar(); 22 } 23 return as * fu; 24 } 25 const int N = 2005; 26 const int M = 10005; 27 typedef double D; 28 #define eps 1e-9 29 //head 30 int s = N-2,t = N-1; 31 int head[N],nxt[M],mo[M],cnt = 1; 32 D cst[M]; 33 void _add(int x,int y,D w) { 34 mo[++cnt] = y; 35 cst[cnt] = w; 36 nxt[cnt] = head[x]; 37 head[x] = cnt; 38 } 39 void add(int x,int y,D w) { 40 if(x^y) _add(x,y,w),_add(y,x,0.0); 41 } 42 43 int dep[N],cur[N]; 44 bool bfs() { 45 queue<int> q; 46 memcpy(cur,head,sizeof cur); 47 ms(dep,0),q.push(s),dep[s] = 1; 48 while(!q.empty()) { 49 int x = q.front(); 50 q.pop(); 51 for(int i = head[x];i;i = nxt[i]) { 52 int sn = mo[i]; 53 if(!dep[sn] && cst[i] >= eps) { 54 dep[sn] = dep[x] + 1; 55 q.push(sn); 56 } 57 } 58 } 59 return dep[t]; 60 } 61 62 D dfs(int x,D flow) { 63 if(x == t || flow <= eps) return flow; 64 D res = 0.0; 65 for(int &i = cur[x];i;i = nxt[i]) { 66 int sn = mo[i]; 67 if(dep[sn] == dep[x] + 1 && cst[i] >= eps) { 68 D d = dfs(sn,min(cst[i],flow - res)); 69 if(d) { 70 cst[i] -= d,cst[i^1] += d; 71 res += d; 72 if(res == flow) break; 73 } 74 } 75 } 76 if(res != flow) dep[x] = 0; 77 return res; 78 } 79 80 int m,n; 81 struct node { 82 int x,y; 83 }a[N]; 84 int du[N]; 85 86 D solve(D g) { 87 ms(head,0),cnt = 1; 88 D ans = 0.0; 89 rep(i,1,m) _add(a[i].x,a[i].y,1.0),_add(a[i].y,a[i].x,1.0); 90 rep(i,1,n) { 91 add(s,i,m); 92 add(i,t,m - du[i] + (g * 2.0)); 93 } 94 while(bfs()) ans += dfs(s,inf); 95 return ((D)m*n - ans) / 2.0; 96 } 97 98 bool vis[N]; 99 int sum; 100 int getans(int x) { 101 for(int i = head[x];i;i = nxt[i]) { 102 int sn = mo[i]; 103 if(vis[sn] || cst[i] <= eps) continue; 104 vis[sn] = 1,sum++; 105 getans(sn); 106 } 107 } 108 109 int main() { 110 while(~scanf("%d%d",&n,&m)) { 111 if(m == 0) { 112 printf("1 1 "); 113 continue; 114 } 115 ms(du,0); 116 rep(i,1,m) a[i].x = read(),a[i].y = read(),du[a[i].x]++,du[a[i].y]++; 117 D L = 0,R = (D)m; 118 while(R - L >= eps * 100) { 119 D mid = (L+R) / 2.0; 120 if(solve(mid) >= eps) L = mid; 121 else R = mid; 122 } 123 124 solve(L);//!!! 125 126 sum = 0,ms(vis,0),vis[s] = 1; 127 getans(s); 128 printf("%d ",sum); 129 rep(i,1,n) if(vis[i]) printf("%d ",i); 130 } 131 return 0; 132 }