• 洛谷3705 [SDOI2017] 新生舞会 【01分数规划】【KM算法】


    题目分析:

    裸题。怀疑$ O(n^4log{n}) $跑不过,考虑Edmonds-Karp优化。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn =  120;
     5 
     6 const double eps = 1e-7;
     7 
     8 int n;
     9 
    10 int a[maxn][maxn],b[maxn][maxn];
    11 
    12 double lx[maxn],ly[maxn],c[maxn][maxn];
    13 int inS[maxn],inT[maxn],Left[maxn];
    14 double slack[maxn];
    15 
    16 void read(){
    17     scanf("%d",&n);
    18     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    19     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&b[i][j]);
    20 }
    21 
    22 int match(int now){
    23     inS[now] = 1;
    24     for(int i=1;i<=n;i++){ 
    25     if(inT[i]) continue;
    26     if(lx[now]+ly[i] - c[now][i] <= eps){
    27         inT[i] = 1;
    28         if(!Left[i] || match(Left[i])){
    29         Left[i] = now;
    30         return true;
    31         }
    32     }else slack[i] = min(slack[i],lx[now]+ly[i]-c[now][i]);
    33     }
    34     return false;
    35 }
    36 
    37 void update(){
    38     double pp = 1e9;
    39     for(int i=1;i<=n;i++) if(!inT[i]) pp = min(pp,slack[i]);
    40     for(int i=1;i<=n;i++){
    41     if(inS[i]) lx[i] -= pp;
    42     if(inT[i]) ly[i] += pp;
    43     else slack[i] -= pp;
    44     }
    45 }
    46 
    47 bool KM(double now){
    48     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j] = a[i][j]-now*b[i][j];
    49     for(int i=1;i<=n;i++) {
    50     lx[i] = -1E9,ly[i] = 0; Left[i] = 0;
    51     for(int j=1;j<=n;j++) lx[i] = max(lx[i],c[i][j]);
    52     }
    53     for(int i=1;i<=n;i++){
    54     for(int j=1;j<=n;j++) slack[j] = 1e9;
    55     for(;;){
    56         for(int j=1;j<=n;j++) inS[j] = inT[j] = 0;
    57         if(match(i)) break;
    58         update();
    59     }
    60     }
    61     double ans = 0;
    62     for(int i=1;i<=n;i++) ans += lx[i] + ly[i];
    63     if(ans <0) return false;
    64     else return true;
    65 }
    66 
    67 double divide(double l,double r){
    68     if(r-l <= eps) return l;
    69     double mid = (l+r)/2.0;
    70     int flag = KM(mid);
    71     if(flag) return divide(mid,r);
    72     else return divide(l,mid);
    73 }
    74 
    75 int main(){
    76     read();
    77     printf("%.6lf",divide(0,1E4));
    78     return 0;
    79 }
  • 相关阅读:
    C# Nugut CsvHelper 使用
    C# 读写txt
    Js打开QQ聊天对话窗口
    Js 读写Cookies
    js 计算时间差
    C# 读取CSV文件
    使用 SqlBulkCopy 批量插入数据
    sql 添加列并设置默认值
    C# 获取Enum 描述和值集合
    SQL连接其它服务器操作
  • 原文地址:https://www.cnblogs.com/Menhera/p/9117690.html
Copyright © 2020-2023  润新知