zoukankan      html  css  js  c++  java
  • P3705 [SDOI2017]新生舞会 分数规划+费用流

    题意:

    戳这里

    分析:

    模拟赛出了这道题的弱化版,把矩阵从 (n^2) 变成了 (2 imes n) 的,被巨佬们用模拟退火退过去了。。。

    现在我们考虑正解,题意等价于,从矩阵中选出 (n) 个点,满足任意两个点不属于同一行或列,求 (frac{sum a}{sum b}) 的最大值

    我们发现这个式子长得很分数规划,所以我们化简得到 (sum a-ans*sum b=0) ,也就是说矩形内部每一个点的权值变成了 (a-ans imes b) 然后每行每列选一个点,使所有点的权值之和最大,既要满足个数要求和限制条件,同时还要求出最大代价,我们发现这不就是费用流

    我们按照分数规划二分得到的值,将行 (i) 和列 (j) 之间连一条流量为 (1) 费用为 (ans*b[i][j]-a[i][j]) 的边,然后原点和每一行连一条流量为 (1) 费用为 (0) 的边,每一列和汇点连一条流量为 (1) 费用为 (0) 的边,这样直接跑网络流,我们就能保证最大流的情况下得到 (sum b*ans-sum a) 的最小值 (等价于 (sum a-ans imes sum b) 的最大值)

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
        int read()
        {
            int x=0,f=1;char ch=getchar();
            while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
        
        const double eps = 1e-8;
        const int maxn = 205;
        const int maxm = 1e5+5;
        int n,cnt=1,st,ed;
        int a[maxn][maxn],b[maxn][maxn];
        int head[maxn],lst[maxn],pre[maxn],flow[maxn];
        bool vis[maxn];
    	double dis[maxn];
        queue<int> q;
    
        struct edge
        {
            int to,nxt,w;
            double cst;
        }e[maxm];
    
        void add(int u,int v,double w,int x)
        {
            e[++cnt].to=v;
            e[cnt].cst=w;
            e[cnt].w=x;
            e[cnt].nxt=head[u];
            head[u]=cnt;
        }
    
        bool spfa()
    	{
    		for(int i=st;i<=ed;i++) pre[i]=-1,vis[i]=false,dis[i]=1000000.0,flow[i]=0x3f3f3f3f;
    		dis[st]=0;
    		q.push(st);
    		while(!q.empty())
    		{
    			int u=q.front();q.pop();
    			vis[u]=false;
    			for(int i=head[u];i;i=e[i].nxt)
    			{
    				int v=e[i].to;
    				if(e[i].w&&dis[v]>dis[u]+e[i].cst)
    				{
    					dis[v]=dis[u]+e[i].cst;
    					pre[v]=u;
    					lst[v]=i;
    					flow[v]=min(flow[u],e[i].w);
    					if(!vis[v])
    					{
    						vis[v]=true;
    						q.push(v);
    					}
    				}
    			}
    		}
    		return pre[ed]!=-1;
    	}
    	
    	double MCMF()
    	{
    		double res=0;
    		while(spfa())
    		{
    			int now=ed;
    			res+=dis[now]*flow[now];
    			while(now!=st)
    			{
    				e[lst[now]].w-=flow[ed];
    				e[lst[now]^1].w+=flow[ed];
    				now=pre[now];
    			}
    		}
    		return res;
    	}
    
        bool check(double x)
        {
            cnt=1;memset(head,0,sizeof(head));
            for(int i=1;i<=n;i++)
            {
                add(st,i,0,1);add(i,st,0,0);
                add(i+n,ed,0,1);add(ed,n+i,0,0);
            }
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    add(i,j+n,x*b[i][j]-a[i][j],1);add(j+n,i,-x*b[i][j]+a[i][j],0);
                }
            }
            return MCMF()<0;
        }
    
        void solve()
        {
            double l=0,mid,r=1000000.0,ans;
            while(r-l>eps)
            {
                mid=(l+r)/2.0;
                if(check(mid))
                {
                    ans=mid;
                    l=mid+eps;
                }
                else r=mid-eps;
            }
            printf("%.6f
    ",ans);
        }
    
        void init()
        {
            n=read();st=0;ed=n*2+1;
            for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=read();
            for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) b[i][j]=read();
        }
    
        void work()
        {
            init();
            solve();
        }
    
    }
    
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    计算机视觉资源合集
    EMZ-搭建DL模型的最简便的方式 | 附项目地址
    在边缘设备上拟合大型神经网络的方法总结
    归一化方法总结 | 又名“BN和它的后浪们“
    名词解释 | 论文中的Ablation study
    知识蒸馏的简要概述
    如何看待计算机视觉未来的走向(二)从产品的角度聊一聊
    STL源码分析--functional
    STL源码分析--algorithm
    STL源码分析--bitset
  • 原文地址:https://www.cnblogs.com/youth518/p/14209409.html
Copyright © 2011-2022 走看看