洛谷
题目描述略
题解时间
$ (\frac{\Sigma EdgeCount}{\Sigma PointCount})_{max} $
是什么已经不用说了⑧
经典的01分数规划
上来先二分答案$ ans $
之后考虑判断
根据选边与选点的关系
考虑建出这样一个图:
建立源点 $ S $ 与汇点 $ P $
对于原图中的每条边看做一个点,从 $ S $ 向这个点建流量为 $ 1 $ 的边
对于原图中的每个点向 $ T $ 建流量为 $ ans $ 的边
对于原图中的每条边所代表的点,向这条边连接的两个点建流量为 $ 1 $ 的边
跑最大流, $ maxflow \leq m $ 即可
原理?
我们回顾一下柿子
$ \frac{\Sigma EdgeCount}{\Sigma PointCount} \leq ans $
转换一下就是
$ \Sigma EdgeCount-\Sigma PointCount*ans \leq 0 $
好像已经很明显了⑧
那就先这样吧(溜走)
#include
#include
#include
#include
using namespace std;
namespace LarjaIX
{
const int N=2011;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double dinf=1e8;
struct sumireko{int to,ne;double w;}e[N<<2];
int he[N],ecnt=1;
void addline(int f,int t,double w)
{
e[++ecnt].to=t,e[ecnt].w=w;
e[ecnt].ne=he[f],he[f]=ecnt;
e[++ecnt].to=f,e[ecnt].w=0;
e[ecnt].ne=he[t],he[t]=ecnt;
}
int head[N],dep[N];
queueq;
bool ins[N];
bool bfs(int sp,int ep)
{
memcpy(head,he,sizeof(head));
memset(dep,0x3f,sizeof(dep));
dep[sp]=1,q.push(sp);
while(!q.empty())
{
int x=q.front();q.pop();
for(int ei=he[x],t=e[ei].to;ei;ei=e[ei].ne,t=e[ei].to)
if(dep[t]==inf&&e[ei].w>eps) dep[t]=dep[x]+1,q.push(t);
}
return dep[ep]!=inf;
}
double dfs(int x,double lim,int ep)
{
if(x==ep||limeps)
{
lim-=tmp,ret+=tmp;
e[ei].w-=tmp,e[ei^1].w+=tmp;
if(limeeps)
{
ansm=(ansl+ansr)/2;
for(int i=1;i<=m;i++) addline(n+i,lx[i],1.0),addline(n+i,ly[i],1.0);
for(int i=1;i<=m;i++) addline(n+m+1,n+i,1.0);
for(int i=1;i<=n;i++) addline(i,n+m+2,ansm);
double tmp=dinic(n+m+1,n+m+2);
if((double)m-tmp>eps) ansl=ansm;
else ansr=ansm;
ecnt=1,memset(he,0,sizeof(he));
}
ansm=ansl;
for(int i=1;i<=m;i++) addline(n+i,lx[i],dinf),addline(n+i,ly[i],dinf);
for(int i=1;i<=m;i++) addline(n+m+1,n+i,1.0);
for(int i=1;i<=n;i++) addline(i,n+m+2,ansm);
dinic(n+m+1,n+m+2);
bfs(n+m+1,n+m+2);
int ans=0;
for(int i=1;i<=n;i++) if(dep[i]!=inf) ans++;
printf("%d\n",ans);
for(int i=1;i<=n;i++) if(dep[i]!=inf) printf("%d\n",i);
ecnt=1,memset(he,0,sizeof(he));
}
return 0;
}
}
int main(){return LarjaIX::maid();}