[SDOI 2017] 新生舞会

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=4819

[算法]

        很明显的0 / 1分数规划问题

        首先二分答案 , 显然 , 若 sigma(Aij - mid * Bij) >= 0 , 说明有比mid更优的解

        用费用流 / KM算法检验即可

        时间复杂度 : O(N^3logN)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
const double inf = 1e15;
const double EPS = 1e-9;

int n;
double delta;
int match[MAXN];
int a[MAXN][MAXN] , b[MAXN][MAXN];
double la[MAXN] , lb[MAXN];
double c[MAXN][MAXN];
bool visiteda[MAXN] , visitedb[MAXN];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline bool dfs(int u)
{
        visiteda[u] = true;
        for (int i = 1; i <= n; i++)
        {
                if (!visitedb[i])
                {
                        if (fabs(la[u] + lb[i] - c[u][i]) < EPS) 
                        {
                                visitedb[i] = true;
                                if (!match[i] || dfs(match[i]))
                                {
                                        match[i] = u;
                                        return true;
                                }
                        } else chkmin(delta , la[u] + lb[i] - c[u][i]);
                }
         }
         return false;
}
inline double KM()
{
        for (int i = 1; i <= n; i++)
        {
                la[i] = -inf;
                lb[i] = 0;
                match[i] = 0;
                for (int j = 1; j <= n; j++) chkmax(la[i] , c[i][j]);
        }
        for (int i = 1; i <= n; i++)
        {
                while (true)
                {
                        delta = inf;
                        for (int j = 1; j <= n; j++) visiteda[j] = visitedb[j] = false;
                        if (dfs(i)) break;
                        for (int j = 1; j <= n; j++) 
                        {
                                if (visiteda[j]) la[j] -= delta;
                                if (visitedb[j]) lb[j] += delta;
                        }
                }
        }
        double ret = 0;
        for (int i = 1; i <= n; i++) ret += c[match[i]][i];
        return ret;
}
inline bool check(double mid)
{
        for (int i = 1; i <= n; i++)
        {
                for (int j = 1; j <= n; j++)
                {
                        c[i][j] = 1.0 * a[i][j] - 1.0 * b[i][j] * mid;        
                }        
        }        
        if (KM() >= 0) return true;
        else return false;
}

int main()
{
        
        read(n);
        for (int i = 1; i <= n; i++)
        {
                for (int j = 1; j <= n; j++)
                {
                        read(a[i][j]);
                }
        }
        for (int i = 1; i <= n; i++)
        {
                for (int j = 1; j <= n; j++)
                {
                        read(b[i][j]);
                }
        }
        double l = 0 , r = (int)1e4 , ans = 0;
        while (l + EPS < r)
        {
                double mid = (l + r) / 2.0;
                if (check(mid))
                {
                        ans = mid;
                        l = mid;        
                }    else r = mid;
        }
        printf("%.6lf\n" , ans);
        
        return 0;
    
}

 

posted @ 2018-10-26 20:07  evenbao  阅读(182)  评论(0编辑  收藏  举报