Loading

UVA1389 Hard Life

题意

给定一张无向图 \(G\),求它的一个导出子图 \(G'=\{V,E\}\),使得 \(\dfrac{|E|}{|V|}\) 最大。

Solution

求分数的最大值,首先想到分数规划。按套路二分当前的答案 \(mid\),那么有:

\[\dfrac{|E|}{|V|}>mid\Leftrightarrow |E|>mid|V|\Leftrightarrow |E|-mid|V|>0 \]

考虑导出子图的限制。按照定义,如果一条边在子图中,那么两个端点也必然在子图中。对点建点,对边建点,然后边向对应的端点连有向边。此时如果边的权值是 \(1\),点的权值是 \(-mid\),就转化成一个最大权闭合子图的问题。

关于最大权闭合子图

建超级源点和超级汇点,然后源点连向正权点,容量是点权,负权点连向汇点,容量是负点权。原图内的边容量为 \(\infty\)。最大权值和就是正权和减去最小割。

听说这个东西叫做最大密度子图。

Code

#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pb emplace_back
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) (a).begin(),(a).end()
#define siz(a) (int)(a).size()
#define clr(a) memset(a,0,sizeof(a))
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<'='<<a<<' '
#define pts(a) cerr<<#a<<'='<<a<<'\n'
// #define int long long
using namespace std;
const double eps=1e-6;
const int MAXN=2110;
struct Edge{int to;double fl,cp;};
vector<Edge> g;
vector<int> e[MAXN];
void add(int u,int v,double w){
    g.pb(Edge{v,0,w});e[u].pb(siz(g)-1);
    g.pb(Edge{u,0,0});e[v].pb(siz(g)-1);
}
int S,T,d[MAXN];
bool bfs(){
    queue<int> q;q.push(S);
    clr(d);d[S]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int s:e[x]){
            if(g[s].fl>=g[s].cp) continue;
            if(d[g[s].to]) continue;
            d[g[s].to]=d[x]+1;
            q.push(g[s].to);
            if(g[s].to==T) return 1;
        }
    }return 0;
}
int cur[MAXN];
double dfs(int x,double a){
    if(x==T||a<=0) return a;
    double fl=0,f;
    for(int &i=cur[x];i<siz(e[x]);i++){
        int s=e[x][i];
        if(d[g[s].to]!=d[x]+1) continue;
        if((f=dfs(g[s].to,min(a,g[s].cp-g[s].fl)))<=0) continue;
        fl+=f;a-=f;g[s].fl+=f;g[s^1].fl-=f;
        if(a<=0) break;
    }return fl;
}
int a[MAXN],b[MAXN],n,m;
bool check(double mid){
    rep(i,0,n+m+1) e[i].clear();
    g.clear();S=n,T=n+m+1;
    rep(i,1,m)
        add(n+i,a[i],10000000000),
        add(n+i,b[i],10000000000);
    rep(i,1,n) add(i,T,mid);
    rep(i,1,m) add(S,n+i,1);
    double sum=0;
    while(bfs()){clr(cur);sum+=dfs(S,10000000000);}
    return m>sum;
}
bool vis[MAXN];
void getans(int x){
	vis[x]=1;
	for(int s:e[x]){
		if(!vis[g[s].to]&&g[s].fl<g[s].cp)
			getans(g[s].to);
	}
}
void solve(){
    rep(i,1,m) cin>>a[i]>>b[i];
    double l=0,r=10000;
    while(r-l>eps){
        double mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }check(l);
    memset(vis,0,sizeof(vis));
    getans(S);
    vector<int> ans;
    rep(i,1,n) if(vis[i]) ans.pb(i);
    cout<<siz(ans)<<'\n';
    for(int v:ans) cout<<v<<'\n';
    cout<<'\n';
    rep(i,S,T) e[i].clear();g.clear();
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    while(cin>>n>>m) solve();
    return 0;
}
posted @ 2022-11-22 20:13  ZCETHAN  阅读(32)  评论(0编辑  收藏  举报