• luoguP3705 [SDOI2017]新生舞会


    题意

    看见这个式子就知道应该(0-1)分数规划了。

    (S)向每个男生连容量为(1)费用为(0)的边,从没个女生向(T)连容量为(1)费用为(0)的边。

    二分答案(mid)

    对于点对((i,j))(i)是男生,(j)是女生,从(i)(j+n)连容量为(1)费用为(a_{i,j}-mid*b_{i,j})的边。

    之后跑最大费用最大流,可行则费用大于等于(0)

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=210;
    const double inf=1000000000;
    const double eps=1e-8;
    int n,cnt_edge=1,S,T;
    int head[maxn];
    double sum;
    double dis[maxn];
    double a[maxn][maxn],b[maxn][maxn];
    bool vis[maxn];
    struct edge{int to,nxt,flow;double cost;}e[maxn*maxn*4];
    inline void add(int u,int v,int w,double c)
    {
    	e[++cnt_edge].nxt=head[u];
    	head[u]=cnt_edge;
    	e[cnt_edge].to=v;
    	e[cnt_edge].flow=w;
    	e[cnt_edge].cost=c;
    }
    inline void addflow(int u,int v,int w,double c){add(u,v,w,c);add(v,u,0,-c);}
    inline bool spfa()
    {
        memset(vis,0,sizeof(vis));
     	for(int i=S;i<=T;i++)dis[i]=-inf;
        queue<int>q;
        q.push(S);dis[S]=0;vis[S]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();vis[x]=0;
            for(int i=head[x];i;i=e[i].nxt)
            {
                if(e[i].flow<=0)continue;
                int y=e[i].to;
                if(dis[y]<dis[x]+e[i].cost)
                {
                    dis[y]=dis[x]+e[i].cost;
                    if(!vis[y])q.push(y),vis[y]=1;
                }
            }
        }
        return dis[T]!=-inf;
    }
    int dfs(int x,int lim)
    {
    	vis[x]=1;
        if(lim<=0||x==T)return lim;
        int res=lim;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(e[i].flow<=0||vis[y]||dis[y]!=dis[x]+e[i].cost)continue;
    		int tmp=dfs(y,min(res,e[i].flow));
            res-=tmp;
            e[i].flow-=tmp,e[i^1].flow+=tmp;
    		if(res<=0)break;
        }
        return lim-res;
    }
    inline double Dinic()
    {
        int res=0;double cost=0;
        while(spfa())
        {
            int flow=dfs(S,inf);
     	    res+=flow,cost+=1.0*dis[T]*flow;
        }
        return cost;
    }
    inline bool check(double mid)
    {
    	memset(head,0,sizeof(head));
    	cnt_edge=1;
    	S=0,T=2*n+1;
    	for(int i=1;i<=n;i++)addflow(S,i,1,0),addflow(i+n,T,1,0);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			addflow(i,j+n,1,a[i][j]-mid*b[i][j]);
    	return Dinic()>=0;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%lf",&a[i][j]),sum+=a[i][j];
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%lf",&b[i][j]);
    	double l=0,r=sum,ans=0;
    	while(r-l>eps)
    	{
    		double mid=(l+r)/2.0;
    		if(check(mid))ans=mid,l=mid+eps;
    		else r=mid-eps;
    	}
    	printf("%.6lf",ans);
    	return 0;
    }
    
  • 相关阅读:
    react-custom-scrollbars的使用
    【react】Mobx总结以及mobx和redux区别
    【React】Redux入门 & store体验
    chrome安装react-devtools开发工具
    【vue】vuex防止数据刷新数据刷掉
    搭建博客的两个工具区别
    JavaScript中的作用域
    通过JavaScript创建表格
    JavaScript中的普通for循环和 for in循环
    JavaScript中创建默认对象的方式
  • 原文地址:https://www.cnblogs.com/nofind/p/12106372.html
Copyright © 2020-2023  润新知