• [BZOJ4819][SDOI2017]新生舞会


    [BZOJ4819][SDOI2017]新生舞会

    bzoj
    luogu

    题意

    (n)个男孩子和(n)个女孩子。他们之间要两两结伴跳舞。
    已知第(i)个男孩子和第(j)个女孩子结伴跳舞会有两个参数(a_{i,j})(b_{i,j})
    现在要求一个安排方案使得(a_{i,j})的总和除以(b_{i,j})的总和的商尽量大。
    形式化地,就是求一个长度为(n)的排列({p_i}),最大化(L=frac{sum_{i=1}^{n}a_{i,p_i}}{sum_{i=1}^{n}b_{i,p_i}})

    sol

    分数规划。
    二分一个答案(mid),把所有匹配边的权值设为(a_{i,j}-mid*b_{i,j})
    接下来就是要求是否存在一个权值和大于(0)的完美匹配。
    费用流直接上了。跑的好慢啊qaq

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 105;
    const double eps = 1e-8;
    struct edge{int to,nxt,w;double cost;}G[N*N<<2];
    int n,a[N][N],b[N][N],head[N<<1],cnt,S,T,vis[N<<1],pe[N<<1];
    double dis[N<<1],ans;queue<int>Q;
    void link(int u,int v,int w,double cost){
    	G[++cnt]=(edge){v,head[u],w,cost};head[u]=cnt;
    	G[++cnt]=(edge){u,head[v],0,-cost};head[v]=cnt;
    }
    bool spfa(){
    	memset(dis,0xfe,sizeof(dis));
    	dis[S]=0;Q.push(S);
    	while (!Q.empty()){
    		int u=Q.front();Q.pop();
    		for (int e=head[u];e;e=G[e].nxt){
    			int v=G[e].to;
    			if (G[e].w&&dis[v]<dis[u]+G[e].cost){
    				dis[v]=dis[u]+G[e].cost;pe[v]=e;
    				if (!vis[v]) vis[v]=1,Q.push(v);
    			}
    		}
    		vis[u]=0;
    	}
    	if (dis[T]==dis[0]) return false;
    	ans+=dis[T];
    	for (int i=T;i!=S;i=G[pe[i]^1].to)
    		--G[pe[i]].w,++G[pe[i]^1].w;
    	return true;
    }
    bool check(double k){
    	memset(head,0,sizeof(head));cnt=1;
    	for (int i=1;i<=n;++i) link(S,i,1,0),link(i+n,T,1,0);
    	for (int i=1;i<=n;++i)
    		for (int j=1;j<=n;++j)
    			link(i,j+n,1,(double)a[i][j]-k*b[i][j]);
    	ans=0;
    	while (spfa()) ;
    	return ans>-eps;
    }
    int main(){
    	n=gi();S=2*n+1;T=S+1;
    	for (int i=1;i<=n;++i)
    		for (int j=1;j<=n;++j)
    			a[i][j]=gi();
    	for (int i=1;i<=n;++i)
    		for (int j=1;j<=n;++j)
    			b[i][j]=gi();
    	double l=0,r=10000;
    	while (r-l>eps){
    		double mid=(l+r)/2;
    		if (check(mid)) l=mid;
    		else r=mid;
    	}
    	printf("%.6lf
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    AngularJS 国际化——Angular-translate
    Elasticsearch Span Query跨度查询
    Elasticsearch 连接查询
    Elasticsearch DSL中Query与Filter的不同
    Lucene查询语法详解
    Elasticsearch 文件目录解释
    Elasticsearch 安装与启动
    《大屏可视化数据》该怎么设计?
    两个大屏可视化案例的布局与实现
    maven 安装后变成 mvn 不是内部命令解决方法
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9060714.html
Copyright © 2020-2023  润新知