#最大密度子图,0/1分数规划#UVA1389 Hard Life


题目

\(n\) 个点,\(m\) 条边的一个无向图,问导出子图的边数除以点数的最大值


分析

考虑二分这个答案,也就是0/1分数规划之后转换成 \(E-mid*V>0\)

这个问题虽然可以精确到具体的最小割,但是也可以泛化到一般的问题。

可以发现转换成最大权闭合子图,源点连边,汇点连点,边和点之间连 \(inf\)

然后最后就是在残余网络上记录哪些点可以被访问,就是导出子图的点。

所以最大密度子图的问题都可以转化成最大权闭合子图吧。


代码

#include 
#include 
using namespace std;
const int N=1111; typedef double db;
struct node{int y; db w; int next;}e[N<<3];
int dis[N],as[N],et=1,X[N],tot,Y[N],v[N],mark[N],b[N],n,m,S,T;
void add(int x,int y,db w){
	e[++et]=(node){y,w,as[x]},as[x]=et;
	e[++et]=(node){x,0,as[y]},as[y]=et;
}
bool bfs(int st){
	for (int i=1;i<=T;++i) dis[i]=0;
	queueq; q.push(st),dis[st]=1;
	while (!q.empty()){
		int x=q.front(); q.pop();
		for (int i=as[x];i;i=e[i].next)
		if (e[i].w>0&&!dis[e[i].y]){
			dis[e[i].y]=dis[x]+1;
			if (e[i].y==T) return 1;
			q.push(e[i].y);
		}
	}
	return 0;
}
db min(db a,db b){return a0&&dis[e[i].y]==dis[x]+1){
		f=dfs(e[i].y,min(now-rest,e[i].w)),
		rest+=f,e[i].w-=f,e[i^1].w+=f;
		if (now==rest) return now;
	}
	if (!rest) dis[x]=0;
	return rest;
}
bool check(db mid){
	for (int i=2;i<=et;i+=2) e[i].w+=e[i^1].w,e[i^1].w=0;
	for (int i=1;i<=n;++i) e[mark[i]].w=mid;
	db ans=m;
	while (bfs(S)) ans-=dfs(S,1e9);
	return ans>1e-8;
}
void Dfs(int x){
	v[x]=1;
	for (int i=as[x];i;i=e[i].next)
	    if (!v[e[i].y]&&e[i].w) Dfs(e[i].y);
}
int main(){
	ios::sync_with_stdio(0);
	while (cin>>n>>m){
		if (!m) {cout<<"1\n1\n\n"; continue;}
		for (int i=1;i<=m;++i) cin>>X[i]>>Y[i];
		S=n+m+1,T=S+1,et=1;
		for (int i=1;i<=m;++i) add(S,i+n,1);
		for (int i=1;i<=n;++i) add(i,T,0),mark[i]=et-1;
		for (int i=1;i<=m;++i) add(i+n,X[i],1e9),add(i+n,Y[i],1e9);
		db l=1.0/n,r=m,eps=1.0/(n*n);
		while (l+eps

相关