【费用流】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; }
总结:一般含有负权或负环或稀疏图、或者流量较小而费用较大时,用spfa的模版,其他zkw即可