• BZOJ4819 [Sdoi2017]新生舞会 【01分数规划 + 费用流】


    题目

    学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会
    买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出
    a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,
    比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,
    还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。C
    athy找到你,希望你帮她写那个程序。一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是a'1,a'2,...,a'n,
    假设每对舞伴的不协调程度分别是b'1,b'2,...,b'n。令
    C=(a'1+a'2+...+a'n)/(b'1+b'2+...+b'n),Cathy希望C值最大。

    输入格式

    第一行一个整数n。
    接下来n行,每行n个整数,第i行第j个数表示a[i][j]。
    接下来n行,每行n个整数,第i行第j个数表示b[i][j]。
    1<=n<=100,1<=a[i][j],b[i][j]<=10^4

    输出格式

    一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等

    输入样例

    3

    19 17 16

    25 24 23

    35 36 31

    9 5 6

    3 4 2

    7 8 9

    输出样例

    5.357143

    题解

    看到比值,01分数规划就很明显了

    我们二分答案(c),建立二分图,连边(a_{(i,j)} - c * b_{(i,j)})
    跑最大费用最大流检验即可

    【卡卡常就卡进去了】

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (register int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 205,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int h[maxn],ne = 2;
    struct EDGE{int to,nxt,f; double w;}ed[maxm];
    inline void build(int u,int v,int f,double w){
    	ed[ne] = (EDGE){v,h[u],f,w}; h[u] = ne++;
    	ed[ne] = (EDGE){u,h[v],0,-w}; h[v] = ne++;
    }
    int n,S,T,head,tail,q[maxm];
    int a[maxn][maxn],b[maxn][maxn];
    double d[maxn];
    int minf[maxn],p[maxn],inq[maxn];
    inline double maxcost(){
    	int u; double cost = 0;
    	while (true){
    		for (int i = S; i <= T; i++) d[i] = -INF,inq[i] = minf[i] = 0;
    		q[head = tail = 1] = S; minf[S] = INF; d[S] = 0;
    		while (head <= tail){
    			u = q[head++];
    			inq[u] = false;
    			Redge(u) if (ed[k].f && d[to = ed[k].to] < d[u] + ed[k].w){
    				d[to] = d[u] + ed[k].w; p[to] = k;
    				minf[to] = min(minf[u],ed[k].f);
    				if (!inq[to]) q[++tail] = to,inq[to] = true;
    			}
    		}
    		if (!minf[T]) return cost;
    		cost += minf[T] * d[T];
    		u = T;
    		while (u != S){
    			ed[p[u]].f -= minf[T];
    			ed[p[u] ^ 1].f += minf[T];
    			u = ed[p[u] ^ 1].to;
    		}
    	}
    }
    bool check(double c){
    	ne = 2; memset(h,0,sizeof(h));
    	REP(i,n) build(S,i,1,0),build(n + i,T,1,0);
    	REP(i,n) REP(j,n) build(i,n + j,1,a[i][j] - c * b[i][j]);
    	return maxcost() >= 0;
    }
    int main(){
    	n = read(); S = 0; T = n << 1 | 1;
    	REP(i,n) REP(j,n) a[i][j] = read();
    	REP(i,n) REP(j,n) b[i][j] = read();
    	double l = 0,r = 100000,mid;
    	while (r - l >= 1e-7){
    		mid = (l + r) / 2;
    		if (check(mid)) l = mid;
    		else r = mid;
    	}
    	printf("%.6lf
    ",(l + r) / 2);
    	return 0;
    }
    
    
  • 相关阅读:
    省选测试28
    省选测试27
    省选测试26
    省选测试25
    省选测试24
    省选测试23
    省选测试22
    省选测试21
    关于maven 导入依赖的最终处理问题
    Dubbo 2 之抽取公共接口
  • 原文地址:https://www.cnblogs.com/Mychael/p/8885783.html
Copyright © 2020-2023  润新知