【BZOJ4200】【LOJ2134】【NOI2015】小园丁与老司机(DP,有源汇上下界最小流)

83 篇文章 0 订阅
40 篇文章 0 订阅

Description

https://loj.ac/problem/2134


Solution

Task 1

考虑将所有点以 y y 为第一关键字、x为第二关键字排序。 y y <script type="math/tex" id="MathJax-Element-157">y</script>坐标相同的点放在一起DP。
记录两个前驱。一个是在本行的前驱,如果无需跳到别的点,那么前驱等于自己;另一个是下一行的前驱。DFS一遍就可以把路径找出来了。

Task 2

要求选最少的路径遍历所有的边,直接搞上下界最小流就行了。


Code

很多同学因为这题代码比较长就不想写啊。其实码量还好吧,也就8.4KB左右(逃

/**************************************
 * Au: Hany01
 * Prob: [BZOJ4200][NOI2015]
 * Date: Jul 21st, 2018
 * Email: hany01@foxmail.com
**************************************/

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = j; i < i##_end_; ++ i)
#define For(i, j ,k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define SZ(a) ((int)(a.size()))
#define ALL(a) a.begin(), a.end()
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define x first
#define y second
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define y1 wozenmezhemecaia 
#ifdef hany01
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read() {
    register char c_; register int _, __;
    for (_ = 0, __ = 1, c_ = getchar(); !isdigit(c_); c_ = getchar()) if (c_ == '-')  __ = -1;
    for ( ; isdigit(c_); c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}


const int maxn = 5e4 + 7;

struct Point { int x, y, id; }p[maxn];
bool operator < (Point A, Point B) { return A.y == B.y ? A.x < B.x : A.y < B.y; }

int n;
set<int> G[maxn];


namespace DynamicProgramming
{
    map<int, PII>  dp1, dp2, dp3;
    vector<int> pr[maxn], prl[maxn], now;
    PII range[maxn];
    int Ans, g[maxn], f[maxn];

    inline void DP()
    {
        //x          x+y        x-y
        dp1[0].x = dp2[0].x = dp3[0].x = 0, Set(g, -1);

        For(r, 1, n) {
            //Get the range
            register int l = r, mx;
            while (r < n && p[r + 1].y == p[r].y) ++ r;

            //get g
            For(i, l, r) {
                range[i] = mp(l, r);
                register int x = p[i].x, y = p[i].y;
                if (dp1.find(x) != dp1.end()) chkmax(g[i], dp1[x].x);
                if (dp2.find(x + y) != dp2.end()) chkmax(g[i], dp2[x + y].x);
                if (dp3.find(x - y) != dp3.end()) chkmax(g[i], dp3[x - y].x);
                if (dp1.find(x) != dp1.end() && g[i] == dp1[x].x) pr[i].pb(dp1[x].y);
                if (dp2.find(x + y) != dp2.end() && g[i] == dp2[x + y].x) pr[i].pb(dp2[x + y].y);
                if (dp3.find(x - y) != dp3.end() && g[i] == dp3[x - y].x) pr[i].pb(dp3[x - y].y);
                f[i] = g[i] + 1;
                if (g[i] >= 0) prl[i].pb(i);
            }

            //get f
            mx = -1, now.clear();
            For(i, l, r) {
                if (mx != -1) {
                    if (chkmax(f[i], i - l + 1 + mx)) prl[i] = now;
                    else if (f[i] == i - l + 1 + mx) rep(j, SZ(now)) prl[i].pb(now[j]);
                }
                if (chkmax(mx, g[i])) now.clear(), now.pb(i);
                else if (mx != -1 && mx == g[i]) now.pb(i);
            }
            mx = -1, now.clear();
            Fordown(i, r, l) {
                if (mx != -1) {
                    if (chkmax(f[i], r - i + 1 + mx)) prl[i] = now;
                    else if (f[i] == r - i + 1 + mx) rep(j, SZ(now)) prl[i].pb(now[j]);
                }
                if (chkmax(mx, g[i])) now.clear(), now.pb(i);
                else if (mx != -1 && mx == g[i]) now.pb(i);
                chkmax(Ans, f[i]);

                if (f[i]) {
                    if (chkmax(dp1[p[i].x].x, f[i])) dp1[p[i].x].y = i;
                    if (chkmax(dp2[p[i].x + p[i].y].x, f[i])) dp2[p[i].x + p[i].y].y = i;
                    if (chkmax(dp3[p[i].x - p[i].y].x, f[i])) dp3[p[i].x - p[i].y].y = i;
                }
            }
        }
        printf("%d\n", Ans);

        /*For(i, 1, n) {
            printf("%d: ", p[i].id);
            rep(j, SZ(prl[i])) cout << p[prl[i][j]].id << ' ';
            cout <<"|";
            rep(j, SZ(pr[i])) cout << p[pr[i][j]].id << ' ';
            cout << endl;
        }*/
    }

    static int nxt[maxn], vis[maxn], fin = 0;

    void DFS(int u)
    {
        //cout << "VISIT: " << u <<endl;
        vis[u] = 1;

        if (!u && !fin) {
            fin = 1;
            for ( ; ; ) {
                u = nxt[u];
                if (!u) break;
                printf("%d ", p[u].id);
                if (p[nxt[u]].y == p[u].y && u != nxt[u]) {
                    if (p[nxt[u]].x < p[u].x) {
                        For(i, u + 1, range[u].y) printf("%d ", p[i].id);
                        Fordown(i, u - 1, nxt[u] + 1) printf("%d ", p[i].id);
                    } else {
                        Fordown(i, u - 1, range[u].x) printf("%d ", p[i].id);
                        For(i, u + 1, nxt[u] - 1) printf("%d ", p[i].id);
                    }
                }
                if (nxt[u] == u) u = nxt[u];
            }
            putchar('\n');
            return;
        }

        rep(i, SZ(prl[u])) {
            rep(j, SZ(pr[prl[u][i]])) {
                if (!vis[pr[prl[u][i]][j]]) {
                    nxt[pr[prl[u][i]][j]] = prl[u][i];
                    if (u != prl[u][i]) nxt[prl[u][i]] = u;
                    DFS(pr[prl[u][i]][j]);
                }
                G[pr[prl[u][i]][j]].insert(prl[u][i]);
            }
        }
    }

    inline void FindPath() {
        For(i, 1, n) if (f[i] == Ans) DFS(i);
        //For(i, 1, n) cout << f[i] << ' ' ; cout << endl;
    }

}


namespace NetworkFlow
{

    const int maxm = maxn << 3;

    int beg[maxn], nex[maxm], v[maxm], f[maxm], e = 1, s, t, S, T, deg[maxn], vis[maxn], lev[maxn], cur[maxn];
    //map<int, int> las1, las2, las3;

    inline void add(int uu, int vv, int ff, int mk = 1) {
        v[++ e] = vv, f[e] = ff, nex[e] = beg[uu], beg[uu] = e;
        if (mk) add(vv, uu, 0, 0);
    }

    inline bool BFS(int S, int T) {
        static queue<int> q;
        Set(lev, 0), lev[S] = 1, q.push(S);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (register int i = beg[u]; i; i = nex[i])
                if (f[i] && !lev[v[i]]) lev[v[i]] = lev[u] + 1, q.push(v[i]);
        }
        return lev[T];
    }

    int DFS(int u, int T, int flow)
    {
        if (u == T) return flow;
        int res = flow, t;
        for (register int& i = cur[u]; i; i = nex[i]) if (f[i] && lev[v[i]] == lev[u] + 1) {
            f[i] -= (t = DFS(v[i], T, min(f[i], res))), f[i ^ 1] += t;
            if (!(res -= t)) break;
        }
        return flow - res;
    }

    inline int MaxFlow(int S, int T) {
        register int Flow = 0;
        while (BFS(S, T)) Cpy(cur, beg), Set(vis, 0), Flow += DFS(S, T, INF);
        return Flow;
    }

    void Build()
    {
        //For(i, 0, n) for (set<int>::iterator j =  G[i].begin(); j != G[i].end(); ++ j) cout << i << "--->" << (*j) << endl;

        /*las1[0] = las2[0] = las3[0] = 0;
        For(i, 1, n) {
            if (las1.find(p[i].x) != las1.end()) add(las1[p[i].x], i, INF);
            if (las2.find(p[i].x + p[i].y) != las2.end()) add(las2[p[i].x + p[i].y], i, INF);
            if (las3.find(p[i].x - p[i].y) != las3.end()) add(las3[p[i].x - p[i].y], i, INF);
            las1[p[i].x] = i, las2[p[i].x + p[i].y] = i, las3[p[i].x - p[i].y] = i;
        }*/
        For(i, 0, n) for (set<int>::iterator j =  G[i].begin(); j != G[i].end(); ++ j)
            ++ deg[i], -- deg[*j], add(i, *j, INF);
        s = n + 1, t = s + 1, S = t + 1, T = S + 1;
        For(i, 0, n) {
            add(i, t, INF), add(s, i, INF);
            if (deg[i] > 0) add(i, T, deg[i]);
            else if (deg[i] < 0) add(S, i, -deg[i]);
        }
        add(t, s, INF);
    }

    void Solve()
    {
        int Ans;

        MaxFlow(S, T), Ans = f[e];
        f[e] = f[e ^ 1] = 0, Ans -= MaxFlow(t, s);
        printf("%d\n", Ans);
    }

}


int main()
{
#ifdef hany01
    File("bzoj4200");
#endif

    n = read();
    For(i, 1, n) p[i].x = read(), p[i].y = read(), p[i].id = i;
    sort(p + 1, p + 1 + n);

    DynamicProgramming:: DP(), DynamicProgramming:: FindPath();

    NetworkFlow:: Build(), NetworkFlow:: Solve();

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值