【费用流】HDU 5406 CRB and Apple

通道

题意:选2条不相交的路径,使得包含的点最多,一条路径的定义是h[u] >= h[v] &&  d[u]<= d[v],则u->v可走

思路:太高深的doubility!转自:i和j之间,大于等于a[i]并且小于等于a[j]的数如果超过一定的值的时候,i就不向j连边,因为选2条路径,如果两个点之间夹在他们之间的点很多的话,费用流就不会走那条边了。。

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

typedef long long ll;

template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return true;
}

const int inf = 0x3f3f3f3f;
const int MAX_N = 2007;
const int MAX_M = MAX_N * MAX_N;

struct Edge {
    int u, v, cap, cost, nxt; 
    Edge () {
        
    }
    Edge (int _u, int _v, int _C, int _c, int _n) {
        u = _u, v = _v, cap = _C, cost = _c, nxt = _n;
    }
};

struct edge {
    int u, v, cap, flow, cost, nxt;
    void set(int _u, int _v, int _cap, int _flow, int _cost, int _nxt) {
        u = _u, v = _v, cap = _cap, flow = _flow, cost = _cost, nxt = _nxt;
    }
};

struct mcmf {
    int fst[MAX_N], cc, d[MAX_N], p[MAX_N], a[MAX_N];
    edge e[MAX_M];
    bool in[MAX_N];
    void init() {
        memset(fst, -1, sizeof(fst)); cc = 0;
    }
    void add(int u, int v, int cap, int cost) {
        e[cc].set(u, v, cap, 0, cost, fst[u]), fst[u] = cc++;
        e[cc].set(v, u, 0, 0, -cost, fst[v]), fst[v] = cc++;
    }
    int spfa(int s, int t, int &mf, int &mc) {
        memset(d, 0x3f, sizeof(d));
        memset(in, 0, sizeof(in));
        d[s] = 0, a[s] = inf, in[s] = 1, p[s] = 0;
        queue<int> q; q.push(s);
        while(!q.empty()) {
            int u = q.front(); q.pop(); in[u] = 0;
            for(int i = fst[u]; ~i; i = e[i].nxt) {
                int v = e[i].v;
                if(e[i].cap > e[i].flow && d[v] > d[u] + e[i].cost) {
                    d[v] = d[u] + e[i].cost, p[v] = i;
                    a[v] = min(a[u], e[i].cap - e[i].flow);
                    if(!in[v]) in[v] = 1, q.push(v);
                }
            }
        }
        if(d[t] == inf) return 0;
        mf += a[t], mc += a[t] * d[t];
        int u = t;
        while(u != s) {
            e[p[u]].flow += a[t], e[p[u] ^ 1].flow -= a[t];
            u = e[p[u]].u;
        }
        return 1;
    }
    int go(int s, int t) {
        int ret = 0, mf = 0, mc = 0;
        while(spfa(s, t, mf, mc)) ret = min(ret, mc);
        return ret;
    }
}go;

struct Node {
    int H, D;
    Node () {
        
    }
    Node (int _H, int _D) {
        H = _H, D = _D;
    }
    bool operator < (const Node &rhs) const {
        if (H != rhs.H) return H > rhs.H;
        return D < rhs.D;
    }
} a[MAX_N];

int m;
struct Bit {
    ll bit[MAX_N];
    void clear() {
        memset(bit, 0, sizeof bit);
    }
    void add(int i, ll v) {
        if (i == 0) bit[0] += v;
        else {
            for (;i <= m; i += i & -i)
                bit[i] += v;
        }
    }
    ll query(int i) {
        if (i < 0) return 0;
        else {
            ll re = 0;
            for (;i > 0; i -= i & -i)
                re += bit[i];
            return re;
        }
    }
};

int n, b[MAX_N], cnt[MAX_N][MAX_N];
Bit Tree;

void Clear() {
    Tree.clear();
    go.init();
}

int main() {
    int T; rd(T);
    while (T-- > 0) {
        Clear();
        rd(n);
        m = 0;
        for (int i = 0; i < n; ++i) {
            rd(a[i].H), rd(a[i].D);
            b[++m] = a[i].D;
        }
        if (n <= 2) {
            printf("%d\n", n);
            continue;
        }
        sort(b + 1, b + 1 + m);
        m = unique(b + 1, b + n + 1) - b - 1;
        sort(a, a + n);
        for (int i = 0; i < n; ++i) 
            a[i].D = lower_bound(b + 1, b + m + 1, a[i].D) - b;
        for (int i = 0; i < n; ++i) {
            for (int j = 1; j <= m; ++j) Tree.bit[j] = 0;
            for (int j = i; j < n; ++j) {
                if (a[i].D > a[j].D) continue;
                Tree.add(a[j].D, 1);
                cnt[i][j] = Tree.query(a[j].D);
            }
        }
        int S = 0, T = 2 * n + 1, X = T + 1;
        go.add(S, X, 2, 0);
        for (int i = 0; i < n; ++i) {
            go.add(X, i * 2 + 1, 1, 0);
            go.add(i * 2 + 2, T, 1, 0);    
            go.add(i * 2 + 1, i * 2 + 2, 1, 0);
            for (int j = i + 1; j < n; ++j) {
                if (a[i].D > a[j].D) continue;
                if (cnt[i][j] >= 4) continue;
                go.add(i * 2 + 2, j * 2 + 1, 1, -1);
            }
        }
        int ans = -go.go(S, T) + 2;
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 总结:一般含有负权或负环或稀疏图、或者流量较小而费用较大时,用spfa的模版,其他zkw即可

posted @ 2015-08-20 21:13  mithrilhan  阅读(256)  评论(0编辑  收藏  举报