zoukankan      html  css  js  c++  java
  • 4819: [Sdoi2017]新生舞会(分数规划)

    4819: [Sdoi2017]新生舞会

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1031  Solved: 530
    [Submit][Status][Discuss]

    Description

    学校组织了一次新生舞会,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值最大。
     

    Input

    第一行一个整数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
     

    Output

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

    Sample Input

    3
    19 17 16
    25 24 23
    35 36 31
    9 5 6
    3 4 2
    7 8 9

    Sample Output

    5.357143

    分析

    首先是分数规划,然后用费用流判断。

    $c=frac{a_1+a_2+...+a_k}{b_1+b_2+...+b_k}$

    二分c,如果c满足条件,那么$a_1+a_2+...+a_k geq c*(b_1+b_2+...+b_k)$

    在转化一下$(a_1-c*b_1)+(a_2-c*b_2)...+(a_k-c*b_k) geq 0$

    那么如果选i,j,他们的贡献就是a[i][j]-c*b[i][j],建图跑最大费用流即可。

    可以把贡献取负,然后跑最小流。

    注意要开double的变量

    code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 
     5 using namespace std;
     6 
     7 const int N = 210;
     8 const int INF = 1e9;
     9 const double eps = 1e-8;
    10 
    11 struct Edge{
    12     int from,to,nxt,cap;double cost;
    13 }e[100100];
    14 int head[N],q[100100],pre[N];
    15 bool vis[N];
    16 int tot = 1,n,m,S,T;
    17 int a[N][N],b[N][N];
    18 double dis[N];
    19 
    20 void add_edge(int u,int v,int cap,double cost) {
    21     e[++tot].from = u;e[tot].to = v;e[tot].cap = cap;e[tot].cost = cost;e[tot].nxt = head[u];head[u] = tot;
    22     e[++tot].from = v;e[tot].to = u;e[tot].cap = 0;e[tot].cost = -cost;e[tot].nxt = head[v],head[v] = tot;
    23 }
    24 void Clear() {
    25     tot = 1;
    26     memset(head,0,sizeof(head));
    27 }
    28 bool spfa() {
    29     for (int i=1; i<=T; ++i) 
    30         dis[i] = INF,vis[i] = false;
    31     dis[S] = 0;vis[S] = true;pre[S] = 0;
    32     int L = 1,R = 0;
    33     q[++R] = S;
    34     while (L <= R) {
    35         int u = q[L++];
    36         for (int i=head[u]; i; i=e[i].nxt) {
    37             int v = e[i].to;
    38             if (e[i].cap  && dis[v]-(dis[u]+e[i].cost)>=eps) {
    39                 dis[v] = dis[u] + e[i].cost;
    40                 pre[v] = i;
    41                 if (!vis[v]) q[++R] = v,vis[v] = true;
    42             }
    43         }
    44         vis[u] = false;
    45     }
    46     if (dis[T] == INF) return false;
    47     return true;
    48 }
    49 double MincostMaxflow() { // 返回double 
    50     double Mincost = 0; // double类型 
    51     while (spfa()) {
    52         int minflow = INF;
    53         for (int i=T; i!=S; i=e[pre[i]].from) 
    54             minflow = min(minflow,e[pre[i]].cap);
    55         for (int i=T; i!=S; i=e[pre[i]].from) {
    56             e[pre[i]].cap -= minflow;
    57             e[pre[i] ^ 1].cap += minflow;
    58         }
    59         Mincost += minflow * dis[T];
    60     }
    61     return Mincost;
    62 }
    63 bool check(double x) {
    64     Clear();
    65     for (int i=1; i<=n; ++i) add_edge(S,i,1,0);
    66     for (int i=1; i<=n; ++i) add_edge(i+n,T,1,0);
    67     for (int i=1; i<=n; ++i) 
    68         for (int j=1; j<=n; ++j) 
    69             add_edge(i,j+n,1,-(a[i][j]-1.0*x*b[i][j]));
    70     double ans = MincostMaxflow();
    71     return ans <= 0;
    72 }
    73 int main () {
    74     scanf("%d",&n);
    75     for (int i=1; i<=n; ++i) 
    76         for (int j=1; j<=n; ++j) 
    77             scanf("%d",&a[i][j]);
    78     for (int i=1; i<=n; ++i) 
    79         for (int j=1; j<=n; ++j)
    80             scanf("%d",&b[i][j]);
    81     S = n*2+1;T = n*2+2;
    82     double L = 0.0,R = 10000.0,ans;
    83     while (R-L >= eps) {
    84         double mid = (L + R) / 2;
    85         if (check(mid)) ans = mid,L = mid;
    86         else R = mid;
    87     }
    88     printf("%.6lf",ans);
    89     return 0;
    90 }
  • 相关阅读:
    Flask从负到零的一周
    DOM(一):节点层次-Node类型
    错误处理(三):区分致命错误和非致命错误
    错误处理(二):常见错误类型
    错误处理(一)
    跨域(二)
    跨域(一)
    AJAX(四):XHR2支持的方法
    AJAX(三):GET与POST
    AJAX(二):HTTP头部信息
  • 原文地址:https://www.cnblogs.com/mjtcn/p/8514296.html
Copyright © 2011-2022 走看看