• 【UVA1389】Hard Life(分数规划+网络流)


    点此看题面

    • 给定一张(n)个点(m)条边的无向图,求最大密度子图(即边数除以点数最大的导出子图)。
    • (nle100,mle1000)

    分数规划

    这种问题一看就是分数规划。

    我们直接二分答案(x),则(frac EPge x)就可以写成(E-x imes Pge 0)

    即选择每条边的价值是(1),每个点的价值是(-x)

    最大权闭合子图

    考虑只有选了两个端点,才能选择这条边,是一个经典的最大权闭合子图模型。

    注意有可能不选任何点会取得最优价值,因此我们最大流之后需要加上判断选择的点数不为(0)

    至于如何判断一个点是否被选择,根据最大权闭合子图模型的建图方式,断开与超级汇相连的边表示选择,那么此时就与超级源连通。即从超级源出发存在一条到该点的增广路径,也就是最后一次(BFS)时的(dep ot=-1)

    (O(Dinic))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100
    #define M 1000
    #define INF 1e9
    #define DB double
    using namespace std;
    int n,m;struct line {int x,y;}p[M+5];
    namespace Dinic
    {
    	#define PS (N+M+2)
    	#define ES (N+3*M)
    	#define s (n+m+1)
    	#define t (n+m+2)
    	#define E(x) ((((x)-1)^1)+1)
    	#define add(x,y,f) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f)
    	int ee,lnk[PS+5],cur[PS+5];struct edge {int to,nxt;DB F;}e[2*ES+5];
    	I void Cl() {ee=0;for(RI i=1;i<=t;++i) lnk[i]=0;}
    	I void Add(CI x,CI y,Con DB& f) {add(x,y,f),add(y,x,0);}
    	int q[PS+5],D[PS+5];I bool BFS()
    	{
    		RI i,k,H=1,T=1;for(i=1;i<=t;++i) D[i]=-1;D[q[1]=s]=0;
    		W(H<=T&&!~D[t]) for(i=lnk[k=q[H++]];i;i=e[i].nxt)
    			e[i].F&&!~D[e[i].to]&&(D[q[++T]=e[i].to]=D[k]+1);return ~D[t];
    	}
    	I DB DFS(CI x=s,DB f=INF)
    	{
    		if(x==t||!f) return f;RI i;DB o,g=0;for(i=cur[x];i;i=e[i].nxt)
    		{
    			if(D[e[i].to]^(D[x]+1)||!(o=DFS(e[i].to,min(f,e[i].F)))) continue;
    			if(g+=o,e[i].F-=o,e[E(i)].F+=o,!(f-=o)) break;
    		}return cur[x]=i,g;
    	}
    	I DB MaxFlow(Con DB& x)//最大权闭合子图模型
    	{
    		RI i;for(Cl(),i=1;i<=n;++i) Add(i,t,x);//点向超级汇
    		for(i=1;i<=m;++i) Add(s,n+i,1),Add(n+i,p[i].x,INF),Add(n+i,p[i].y,INF);//超级源向边,边向点
    		DB f=0;W(BFS()) memcpy(cur,lnk,sizeof(cur)),f+=DFS();return f;//最大流
    	}
    	I bool Check(CI x) {return ~D[x];}//判断是否选择(是否与超级源连通)
    }
    int main()
    {
    	RI i,c;DB l,r,mid,res;W(scanf("%d%d",&n,&m)==2)
    	{
    		for(i=1;i<=m;++i) scanf("%d%d",&p[i].x,&p[i].y);
    		if(!m) {puts("1
    1
    ");continue;}//特判没有边的情况
    		l=0,r=m;W(r-l>1e-6) {res=m-Dinic::MaxFlow(mid=(l+r)/2);//分数规划
    			for(i=1;i<=n;++i) if(Dinic::Check(i)) break;i<=n&&res>0?l=mid:r=mid;}//必须有点被选择
    		for(Dinic::MaxFlow(l),c=0,i=1;i<=n;++i) Dinic::Check(i)&&++c;printf("%d
    ",c);
    		for(i=1;i<=n;++i) Dinic::Check(i)&&printf("%d
    ",i);putchar('
    ');
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    在energia中添加新的库
    KEIL3中出现的字符不对齐的情况解决办法
    VHDL硬件描述语言实现数字钟
    51单片机软件I2C驱动中的CY
    自问自答:在VB中如何实现像C++一样printf的功能
    [转][译] 分分钟学会一门语言之 Python 篇
    杂谈PID控制算法——最终篇:C语言实现51单片机中的PID算法
    Eclipse 安装与配置
    win10 环境安装 jdk 11.0.2
    解决网络问题神奇工具
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/UVA1389.html
Copyright © 2020-2023  润新知