裸最大密度子图:参考博客:
点击打开链接,论文:胡伯涛,最小割模型在信息学竞赛中的应用
/** 给定一个无向图,要求它的一个子图,使得子图中边数|E|与点数|V|的比值最大。 解法一: 假设答案为k ,则要求解的问题是:选出一个合适的点集V和边集E,令(|E| - k * |V|) 取得最大值。所谓“合适”是指满足如下限制:若选择某条边,则必选择其两端点。 建图:以原图的边作为左侧顶点,权值为1;原图的点作为右侧顶点,权值为-k(相当于 支出k)。 若原图中存在边(u,v),则新图中添加两条边([uv]-->u), ([uv]-->v),转换为最大权闭合子图。 解法二: 把原图中的无向边转换成两条有向边,容量为1。 设一源点,连接所有点,容量为U(取m)。 设一汇点,所有点连接汇点,容量为 U+2g-dv 。 二分枚举最大密度g,其中dv为v的度。 判断(U*n-MaxFlow)/2.>=0。 最后跳出的L就是最大密度。 拿这个L再重新建图,求最大流。 然后从s出发bfs或者dfs,走残留容量大于0的边,所有能到达的点就是答案。 具体分析过程见胡伯涛的论文《最小割模型在信息学竞赛中的应用》 **/ /** nowcode 第十四届华中科技大学程序设计竞赛决赛同步赛 K */ #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<queue> #include<vector> using namespace std; const int inf = 1e9; const int maxn = 4000; const double eps = 1e-8; typedef long long ll; struct Edge { int fr,to; double cap,flow; }; struct Dinic { int n,m,s,t; vector<Edge>edges; vector<int>G[maxn+5]; bool vis[maxn+5]; int d[maxn+5]; int cur[maxn+5]; void Init(int n) { this->n = n; for(int i=0; i<=n; i++) G[i].clear(); edges.clear(); } void Addedge(int fr,int to,double cap) { edges.push_back((Edge) { fr,to,cap,0 }); edges.push_back((Edge) { to,fr,0,0 }); m = edges.size(); G[fr].push_back(m-2); G[to].push_back(m-1); } bool BFS() { memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(s); d[s] = 0, vis[s] = 1; while(!Q.empty()) { int x = Q.front(); Q.pop(); for(int i=0,l=G[x].size(); i<l; i++) { Edge &e = edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to] = 1; d[e.to] = d[x] + 1; Q.push(e.to); } } } return vis[t]; } double DFS(int x,double a) { if(x==t||a==0) return a; double flow = 0,f; for(int &i=cur[x],l=G[x].size(); i<l ; 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(int s,int t) { this->s = s, this->t = t; double flow = 0; while(BFS()) { memset(cur,0,sizeof(cur)); flow+=DFS(s,(double)inf); } //cout<<flow<<endl; return flow; } }my; int n,a[105],x[10005],y[10005],tot,dv[105]; bool check2(double k) { my.Init(n+2); for(int i=1;i<=tot;i++) { my.Addedge(x[i],y[i],1); my.Addedge(y[i],x[i],1); } for(int i=1;i<=n;i++) { my.Addedge(0,i,tot); my.Addedge(i,n+1,tot+2*k-dv[i]); } return ((tot*n - my.Maxflow(0,n+1))/2 >= eps ); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) if(a[i]%a[j]==0||a[j]%a[i]==0) x[++tot] = i, y[tot] = j, dv[i]++,dv[j]++; } double l = 0,r = n, mid; for(int i=1;i<=30;i++) { mid = (l+r)/2; if(check2(mid)) l = mid; else r = mid; } printf("%.10f\n",l); return 0; }