标签:style blog http color io os ar for sp
Hard Life
做该题前需要先了解一些专有名词及定理。
希望你可以亲自看看2007年胡伯涛的论文!
有向图的闭合图(closure): 闭合图内任意点的任意后继也一定还在闭合图中。
题目:
给出N个人,有些人之间有联系,而有联系的两个人被认为是一个整体。如果,把人看作点,把关系看作边,则要求你求出 边 / 点 的比值最大。而这些点边之间必须是一个闭合图。
算法分析:
最大密度子图算法构造:
把原图中的无向边转换成两条有向边,容量为1。
设一源点,连接所有点,容量为U(取m)。
设一汇点,所有点连接汇点,容量为 U+2g-dv 。
二分枚举最大密度g,其中dv为v的度。
判断(U*n-MaxFlow)/2.>=0。
最后跳出的L就是最大密度。
拿这个L再重新建图,求最大流。
然后从s出发bfs或者dfs,走残留容量大于0的边,所有能到达的点就是答案。
#include <iostream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <cstdio> #include <cstring> using namespace std; typedef pair<int,int> pii; const double INF = 1e7; const double EPS = 1e-7; const int MAXN = 100 + 10; struct Edge{ int from,to; double cap,flow; Edge(){}; Edge(int _from,int _to,double _cap,double _flow) :from(_from),to(_to),cap(_cap),flow(_flow){}; }; pii verter[1010]; vector<Edge> edges; vector<int> G[MAXN]; int d[MAXN],cur[MAXN]; bool vst[MAXN]; int dv[MAXN]; int V,E,S,T; int num; void clr(){ for(int i = 0;i <= T;++i) G[i].clear(); edges.clear(); } void addEdge(int f,int t,double w){ edges.push_back(Edge(f,t,w,0.0)); edges.push_back(Edge(t,f,0.0,0.0)); int sz = edges.size(); G[f].push_back(sz - 2); G[t].push_back(sz - 1); } bool BFS(){ memset(vst,0,sizeof(vst)); queue<int> Q; Q.push(S); d[S] = 0; vst[S] = 1; while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int i = 0;i < (int)G[x].size();++i){ Edge& e = edges[G[x][i]]; if(!vst[e.to] && e.cap > e.flow){ vst[e.to] = 1; d[e.to] = d[x] + 1; Q.push(e.to); } } } return vst[T]; } double DFS(int x,double a){ if(x == T||a == 0) return a; double flow = 0,f; for(int& i = cur[x];i < (int)G[x].size();++i){ Edge& e = edges[G[x][i]]; if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap - e.flow))) > 0){ e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } double maxFlow(){ double flow = 0; while(BFS()){ memset(cur,0,sizeof(cur)); flow += DFS(S,INF); } return flow; } void build(double g){ clr(); for(int i = 0;i < E;++i){ addEdge(verter[i].first,verter[i].second,1.0); addEdge(verter[i].second,verter[i].first,1.0); } for(int i = 1;i <= V;++i){ addEdge(S,i,E*1.0); addEdge(i,T,(1.0*E + 2.0 * g - dv[i])); } } //查找割边 void dfs(int u){ vst[u] = 1; if(u <= V) num++; for(int i = 0;i < (int)G[u].size();++i){ Edge& e = edges[G[u][i]]; if(!vst[e.to] && e.cap > e.flow){ dfs(e.to); } } } void solve(){ double c,lb = 0,ub = E*1.0; for(int k = 0;k < 100;++k){ double mid = (lb + ub) / 2.0; build(mid); c = maxFlow(); c = (E * V * 1.0 - c) / 2.0; if(c > EPS){ lb = mid; } else { ub = mid; } } build(lb); maxFlow(); memset(vst,0,sizeof(vst)); num = 0; dfs(S); printf("%d\n",num); for(int i = 1;i <= V;++i){ if(vst[i]) printf("%d\n",i); } } int main() { // freopen("Input.txt","r",stdin); // freopen("Output.txt","w",stdout); while(~scanf("%d%d",&V,&E)){ int a,b; if(E == 0){ printf("1\n1\n"); continue; } S = V + 1; T = V + 2; memset(dv,0,sizeof(dv)); for(int i = 0;i < E;++i){ scanf("%d%d",&a,&b); verter[i] = make_pair(a,b); dv[a]++; dv[b]++; } solve(); } return 0; }
标签:style blog http color io os ar for sp
原文地址:http://blog.csdn.net/zhongshijunacm/article/details/39780247