UVA1389 Hard Life
题意#
给定一张无向图 ,求它的一个导出子图 ,使得 最大。
Solution#
求分数的最大值,首先想到分数规划。按套路二分当前的答案 ,那么有:
考虑导出子图的限制。按照定义,如果一条边在子图中,那么两个端点也必然在子图中。对点建点,对边建点,然后边向对应的端点连有向边。此时如果边的权值是 ,点的权值是 ,就转化成一个最大权闭合子图的问题。
关于最大权闭合子图
建超级源点和超级汇点,然后源点连向正权点,容量是点权,负权点连向汇点,容量是负点权。原图内的边容量为 。最大权值和就是正权和减去最小割。
听说这个东西叫做最大密度子图。
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?