Codechef RIN

Codechef RIN

最大化平均分本质上就是最大化得分和。但是发现这个东西不太可做,于是规定一个 100 分的满分后就是最小化扣分的和。

对于一个课程,我们先不考虑限制问题,那么可以建立 $ a_1,a_2,\dots ,a_m $ 这 $ m $ 个点,然后 $ s \to a_1 , a_1\to a_2,\dots a_{m-1} \to a_m , a_m \to t $ 这样连,并且 $ a_{i-1} \to a_i $ 的权值就是在第 $ i $ 学期学完这门课的扣分,特别的,$ a_m \to t $ 连 $ \infin $,如果不能学习也连 $ +\infin $ 。如果没有限制,这个图的最小割就是答案了。

现在来考虑限制,对于一个限制,我们可以从 $ a_i $ 向 $ b_{i+1} $ 连一条长度为 $ +\infin $ 的边。考虑这样的正确性,如果从 $ a_k $ 向后割掉了,再从 $ b_k $ 前面的一个地方或者 $ b_k $ 向后割掉了,那么可以通过 $ a_k \to b_{k+1} $ 走到 $ t $ 。

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "queue"
#include "cmath"
#include "vector"
using namespace std;
#define mem(a) memset( a , 0 , sizeof a )
#define MAXN 6006
#define inf 0x3f3f3f3f

typedef long long ll;
class maxFlow {
private:
    int add(int u, int v, ll w) {
        nxt.push_back(head[u]);
        int x = ( head[u] = to.size() );
        to.push_back(v);
        cap.push_back(w);
        return x;
    }
public:
    std::queue<int> q;
    std::vector<int> head, cur, nxt, to, dep;
    std::vector<ll> cap;

    maxFlow(int _n = 0) { init(_n); }
    void init(int _n) {
        head.clear();
        head.resize(_n + 1, 0);
        nxt.resize(2);
        to.resize(2);
        cap.resize(2);
    }
    void init() { init(head.size() - 1); }
    int Add(int u, int v, ll w) {
//      printf("%d %d %d\n",u,v,w);
        add(u, v, w);
        return add(v, u, 0);
    }
    void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
    bool bfs(int s, int t, int delta) {
        dep.clear();
        dep.resize(head.size(), -1);
        dep[s] = 0;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = nxt[i]) {
                int v = to[i];
                ll w = cap[i];
                if (w >= delta && dep[v] == -1) {
                    dep[v] = dep[u] + 1;
                    q.push(v);
                }
            }
        }
        return ~dep[t];
    }
    ll dfs(int u, ll flow, int t, int delta) {
        if (dep[u] == dep[t])
            return u == t ? flow : 0;
        ll out = 0;
        for (int& i = cur[u]; i; i = nxt[i]) {
            int v = to[i];
            ll w = cap[i];
            if (w >= delta && dep[v] == dep[u] + 1) {
                ll f = dfs(v, std::min(w, flow - out), t, delta);
                cap[i] -= f;
                cap[i ^ 1] += f;
                out += f;
                if (out == flow)
                    return out;
            }
        }
        return out;
    }
    ll maxflow(int s, int t) {
        ll out = 0;
        ll maxcap = *max_element(cap.begin(), cap.end());
        for (ll delta = 1ll << int(log2(maxcap) + 1e-12); delta; delta >>= 1) {
            while (bfs(s, t, delta)) {
                cur = head;
                out += dfs(s, 0x7fffffffffffffffll, t, delta);
            }
        }
        return out;
    }
    ll getflow(int x) const { return cap[x << 1 | 1]; }
} F ;
int n , m , k , s = 10001 , t = 10002;
int id( int x , int y ) { return y ? ( x - 1 ) * m + y : s; }
int main() {
    cin >> n >> m >> k;
    F.init( 10004 );
    for( int i = 1 ; i <= n ; ++ i ) {
        for( int j = 1 , w ; j <= m ; ++ j ) {
            scanf("%d",&w);
            F.Add( id( i , j - 1 ) , id( i , j ) , ~w ? 100 - w : inf );
        }
        F.Add( id( i , m ) , t , inf );
    }
    int a , b;
    while( k-- ) {
        scanf("%d%d",&a,&b);
        for( int i = 0 ; i < m ; ++ i ) {
            F.Add( id( a , i ) , id( b , i + 1 ) , inf );
        }
    }
    printf("%.2lf",100 - 1.0 * F.maxflow( s , t ) / n);
}
posted @ 2020-02-20 10:10  yijan  阅读(103)  评论(0编辑  收藏  举报