http://poj.org/problem?id=3155
大致题意:给出一个无向图,求出它的一个最大密度子图,最大密度子图定义为子图的边数与顶点数的比值。
详见amber论文中关于最大密度子图
本题要注意的地方:
当m为0时也要输出内容。
二分的边界是 1/n/n(high - low >1/n/n) ,这在amber论文引理4.1中有讲解
因为h函数的特性,恒有h >=0,即h函数不是一个严格递减的函数,当减小到0时便不再减小。那么我们要取得的是第一个为0的,所以要二分下界,而不是直接取mid,因为没有意识到函数特性,WA了N次。
二分完毕后,并不能求出正确的low值,ms也是因为该函数的特性,我们还要再求一遍最大流。
根据残量网络求最大密度子图:从源点dfs,走残量网络中流量大于0的边并标记。
#include <stdio.h> #include <iostream> #include <algorithm> #include <set> #include <map> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #define LL long long #define _LL __int64 #define eps 1e-8 using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 110; const int maxm = 1010; struct node { int u,v; double w; int next,rev; }p[maxm],edge[maxm*6]; int s,t,n,m,nn; int cnt,head[maxn]; int d[maxn]; int dist[maxn],vis[maxn]; int ans; void init() { cnt = 0; memset(head,-1,sizeof(head)); } void add(int u, int v, double w) { edge[cnt] = (struct node){u,v,w,head[u],cnt+1}; head[u] = cnt++; edge[cnt] = (struct node){v,u,0,head[v],cnt-1}; head[v] = cnt++; } void build(double mid) { init(); for(int i = 1; i <= m; i++) { add(p[i].u,p[i].v,1.0); add(p[i].v,p[i].u,1.0); } for(int i = 1; i <= nn; i++) { add(s,i,m); add(i,t,m*1.0+2*mid-d[i]*1.0); } } bool bfs() { queue <int> que; memset(dist, 0, sizeof(dist)); memset(vis, 0, sizeof(vis)); while(!que.empty()) que.pop(); vis[s] = 1; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(edge[i].w && !vis[v]) { que.push(v); vis[v] = 1; dist[v] = dist[u]+1; } } } if(dist[t] == 0) return false; return true; } double dfs(int u, double delta) { if(u == t) return delta; double ret = 0,tmp; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(edge[i].w && dist[edge[i].v] == dist[u]+1 && (tmp = dfs(v,min(delta,edge[i].w)))) { edge[i].w -= tmp; edge[edge[i].rev].w += tmp; return tmp; } } if(!ret) dist[u] = -1; return ret; } double Dinic() { double ans = 0,res; while(bfs()) { while(res = dfs(s,INF)) ans += res; } return ans; } void dfs_cut(int u) { vis[u] = 1; if(u <= nn) ans++; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(edge[i].w > 0 && !vis[v]) { dfs_cut(v); } } } int main() { while(~scanf("%d %d",&n,&m)) { if(m == 0) { printf("1\n1\n"); continue; } memset(d,0,sizeof(d)); for(int i = 1; i <= m; i++) { scanf("%d %d",&p[i].u,&p[i].v); d[p[i].u]++; d[p[i].v]++; } s = n+1; t = n+2; nn = n; n = t; double low,high,mid,h; low = 0.0; high = m; while(high - low > 1.0/nn/nn) { mid = (high + low)/2; build(mid); h = (m*nn*1.0 - Dinic() )/2; if(h > eps) low = mid; else high = mid; } build(low); Dinic(); ans = 0; memset(vis,0,sizeof(vis)); dfs_cut(s); printf("%d\n",ans); for(int i = 1; i <= nn; i++) { if(vis[i]) printf("%d\n",i); } } return 0; }