【费用流】HDU 5406 CRB and Apple

通道

题意:

思路:

代码:

#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[j].D < a[i].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] >= 5) continue;
                go.add(i * 2 + 2, j * 2 + 1, 1, -1);
            }
        }
        int ans = -go.go(S, T) + 2;
        printf("%d\n", ans);
    }
    return 0;
}

时间: 2024-10-10 05:45:58

【费用流】HDU 5406 CRB and Apple的相关文章

HDU 5406 CRB and Apple 花样费用流向解法

题意简化一下就是一个序列,找出两个最大不下降子序列使得他们的长度和最长. = =作为一个DP渣,状态设计大概也就到了dp[i][j]表示第一个人最后一次取到i,第二个人取到j这个地方了..怎么在可行复杂度内转移?不会啊望天.. 其实作为图论工作者第一反应是费用流,但是边数太多了没敢搞= = 然而其实费用流也是可以过的.(x, y)表示容量为x费用为y, 建图很简单,建源s和汇e,加一个点t限制从 源最多流量是2,也就是s->t(2, 0).将各个点拆掉限制只能取一次,x->x'(1, 1),容

2015 Multi-University Training Contest 10 hdu 5406 CRB and Apple

CRB and Apple Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 421    Accepted Submission(s): 131 Problem Description In Codeland there are many apple trees.One day CRB and his girlfriend decide

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

hdu 4862 Jump 上下界费用流

对于每个点拆点成为两个点a,b,连接a到b的上界为1,下界为1的边,保证用过一次且仅一次. 然后若点u可到达点v,则连接即可.建成了一个上下界网络,将下界拆出去,求最大费用最大流就好. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=800; const int MAXE=200000; const int inf=1<<3

HDU 4406 GPA(网络流-最大费用流)

GPA Problem Description GPA(Grade-Point Average) is one way to measure students' academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an intege

HDU 4862 Jump 最小k路径覆盖 费用流

gg... 题意: 给定n*m的矩阵 选<=k个起点 每个起点可以向右或向下跳任意步 花费是2点间的曼哈顿距离 若2个格子的数字一样 则赚取格子上的数字的价值 问:遍历整个图的最小花费 若不能遍历则输出-1 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set> #in

HDU 3667 Transportation(网络流之费用流)

题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行.但是每条边的流量并不是1,该怎么办呢.这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边.但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来.这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此.然后按照给出的边建图跑一次费用流就可以了. 代码如下: #i

HDU 2485 Destroying the bus stations(费用流)

http://acm.hdu.edu.cn/showproblem.php?pid=2485 题意: 现在要从起点1到终点n,途中有多个车站,每经过一个车站为1时间,现在要在k时间内到达终点,问至少要破坏多少个车站. 思路: 把每个点拆分为两个点,容量为1,费用为0.之后相邻的车站连边,容量为INF,费用为1,表示经过一个车站需要1时间. 这样一来,跑一遍费用流计算出在费用不大于k的情况下的最大流,也就是最小割,即至少要破坏的车站数. 在网络中寻求关于f的最小费用增广路,就等价于在伴随网络中寻求

HDU 4067 Random Maze 费用流

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1114    Accepted Submission(s): 387 Problem Description In the game "A Chinese Ghost Story", there are many random mazes which h