题意:
给定一个含有 个结点, 条边的无向图 ,找出其一个子图 ,其边的条数 和点的个数 的比值,即 最大。(子图 中 ,有 )
要求按编号升序输出任意一个满足条件的子图中的点。
分析:
即求:
对于一个答案猜测值
,构造函数:
设正确答案为
,则有:
所以函数
具有单调性,可以二分查找答案。
对于函数 ,有 ;
所以,可以将 边 均视为点权为1的点,点 的点权均为 ,构成新图,于是求解 即 求解新图的 最大权闭合图。
若原图存在边 ,则新图中建边 与 ,此外,由于容量需定为浮点型,所以比较时要注意精度。
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
const double eps=1e-18;
int s=0,t=maxn-1;
int head[maxn],cnt;
struct edge
{
int u,v;
double w;
int next;
}e[maxn];
void add_edge(int u,int v,double w)
{
e[cnt]=edge{u,v,w,head[u]};
head[u]=cnt++;
e[cnt]=edge{v,u,0,head[v]};
head[v]=cnt++;
}
int dis[maxn];
bool bfs()
{
memset(dis,-1,sizeof(dis));
queue<int> q;
q.push(s);
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(e[i].w>eps&&dis[v]==-1)
{
dis[v]=dis[u]+1;
if(v==t)
return true;
q.push(v);
}
}
}
return false;
}
int cur[maxn];
double dfs(int u,double flow)
{
if(u==t)
return flow;
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(dis[v]==dis[u]+1&&e[i].w>eps)
{
double k=dfs(v,min(flow,e[i].w));
if(k>eps)
{
e[i].w-=k;
e[i^1].w+=k;
return k;
}
}
}
return 0;
}
double dinic()
{
double ans=0;
while(bfs())
{
for(int i=0;i<maxn;i++)
cur[i]=head[i];
while(double k=dfs(s,INF))
ans+=k;
}
return ans;
}
int n,m;
pair<int,int> E[maxn];
bool check(double g)
{
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<=m;i++)
{
add_edge(s,n+i,1);
int u=E[i].first,v=E[i].second;
add_edge(n+i,u,INF);
add_edge(n+i,v,INF);
}
for(int i=1;i<=n;i++)
add_edge(i,t,g);
return m-dinic()>0;
}
vector<int> ans;
bool vis[maxn];
void DFS(int u)
{
vis[u]=true;
if(1<=u&&u<=n)
ans.push_back(u);
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
double w=e[i].w;
if(!vis[v]&&w>eps)
DFS(v);
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d %d",&E[i].first,&E[i].second);
if(m==0)
{
printf("1\n1\n");
return 0;
}
double L=0,R=m,MID;
while(R-L>1e-5)
{
MID=(L+R)/2;
if(check(MID))
L=MID;
else
R=MID;
}
check(L);
DFS(s);
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++)
printf("%d\n",ans[i]);
return 0;
}