1. 程式人生 > 其它 >#最大密度子圖,0/1分數規劃#UVA1389 Hard Life

#最大密度子圖,0/1分數規劃#UVA1389 Hard Life

最大密度子圖,0/1分數規劃

題目

\(n\) 個點,\(m\) 條邊的一個無向圖,問匯出子圖的邊數除以點數的最大值


分析

考慮二分這個答案,也就是0/1分數規劃之後轉換成 \(E-mid*V>0\)

這個問題雖然可以精確到具體的最小割,但是也可以泛化到一般的問題。

可以發現轉換成最大權閉合子圖,源點連邊,匯點連點,邊和點之間連 \(inf\)

然後最後就是在殘餘網路上記錄哪些點可以被訪問,就是匯出子圖的點。

所以最大密度子圖的問題都可以轉化成最大權閉合子圖吧。


程式碼

#include <iostream>
#include <queue>
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;
	queue<int>q; 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 a<b?a:b;}
db dfs(int x,db now){
	if (x==T||!now) return now;
	db rest=0,f;
	for (int i=as[x];i;i=e[i].next)
	if (e[i].w>0&&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<r){
			db mid=(l+r)/2;
			if (check(mid)) l=mid;
			    else r=mid;
		}
		check(l),Dfs(S),tot=0;
		for (int i=1;i<=n;++i) if (v[i]) b[++tot]=i;
		cout<<tot<<endl;
		for (int i=1;i<=tot;++i) cout<<b[i]<<endl;
		cout<<endl;
		for (int i=1;i<=T;++i) as[i]=v[i]=0;
	}
	return 0;
}