BZOJ 4200 NOI 2015 小园丁与老司机

感觉这是NOI2015最有意思的一道题。
如果没有见过类似的 仅有下界的最小流 问题。 先A掉UVa 1440再说

刚刚那篇题解对于这个问题的第三问讲得很详细 , 这里不再赘述求法啦。 但首先 , 我们要DP出所有可能的路径。 其实DP还是挺简单的 , 但是在网络流之前的建图费了我很多时间。 不知道有没有小伙伴有更好的建图方法 , help!!

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <cassert>

using namespace std;
const int maxn = 5e4+1e2;
const int INF = 0x3f3f3f3f;

struct state
{
    int a , b , num;
    state(int a=0 , int b=0 , int num=0):a(a),b(b),num(num){}
    bool operator <(const state& c)const{ return a<c.a || (a==c.a && b<c.b); }
};

struct points
{
    int x , y , num;
    points(int x=0 , int y=0 , int num=0):x(x),y(y),num(num){}
    bool operator <(const points& b)const{ return y<b.y || (y==b.y && x<b.x); }
};

namespace FLOW 
{
    int n;
    int d[maxn] , iter[maxn];
    queue<int> q;

    void init(int _n)
    {
        n = _n;
    }

    struct edge
    {
        int t , c , re;
        edge(int t=0 , int c=0 , int re=0):t(t),c(c),re(re){}
    };

    vector<edge> g[maxn];

    void addEdge(int s , int t , int c , int modi = 0)
    {
        g[s].push_back(edge(t , c , g[t].size()));
        g[t].push_back(edge(s , 0 , g[s].size()-1));

        g[s].back().c -= modi;
        g[t].back().c += modi;
    }

    bool bfs(int s , int t)
    {
        for(int i=0;i<=n;i++) d[i] = -1;
        d[s] = 0;

        q.push(s);
        while(!q.empty())
        {
            int now = q.front(); q.pop();

            for(int i=0;i<g[now].size();i++)
            {
                edge& e = g[now][i];
                if(e.c && d[e.t]==-1)
                {
                    d[e.t] = d[now]+1;
                    q.push(e.t);
                }
            }
        }
        return d[t]!=-1;
    }

    int dfs(int s , int t , int f)
    {
        if(s==t) return f;
        for(int &i = iter[s];i<g[s].size();i++)
        {
            edge& e = g[s][i];
            if(e.c && d[e.t] == d[s] + 1)
            {
                int flow = dfs(e.t, t, min(f , e.c));
                if(flow)
                {
                    e.c -= flow;
                    g[e.t][e.re].c += flow;
                    return flow;
                }
            }
        }
        return 0;
    }

    int maxFlow(int s , int t)
    {
        int res = 0 , f;
        while(bfs(s, t))
        {
            for(int i=0;i<=n;i++) iter[i] = 0;
            while((f = dfs(s, t, INF))) res += f;
        }
        return res;
    }
}

int n;
int d[maxn] , f[maxn] , l[maxn] , r[maxn] , id[maxn] , mark[maxn];

points a[maxn];
state ord[maxn];
map<int, int> lm , rm;
vector<int> g[maxn] , rg[maxn];

void dpPrep()
{
    for(int i=1;i<=n;i++) ord[i] = state(a[i].x , a[i].y , i);
    sort(ord+1, ord+1+n);

    for(int i=1 , j , k;i<=n;i=j+1)
    {
        for(j=i;ord[j+1].a==ord[i].a;j++);
        for(k=i;k<j;k++) 
        g[ord[k].num].push_back(ord[k+1].num) , rg[ord[k+1].num].push_back(ord[k].num);
    }

    for(int i=1;i<=n;i++) ord[i] = state(a[i].x+a[i].y , a[i].y , i);
    sort(ord+1, ord+1+n);

    for(int i=1 , j , k;i<=n;i=j+1)
    {
        for(j=i;ord[j+1].a==ord[i].a;j++);
        for(k=i;k<j;k++) 
        g[ord[k].num].push_back(ord[k+1].num) , rg[ord[k+1].num].push_back(ord[k].num);
    }

    for(int i=1;i<=n;i++) ord[i] = state(a[i].y-a[i].x , a[i].y , i);
    sort(ord+1, ord+1+n);

    for(int i=1 , j , k;i<=n;i=j+1)
    {
        for(j=i;ord[j+1].a==ord[i].a;j++);
        for(k=i;k<j;k++) 
        g[ord[k].num].push_back(ord[k+1].num) , rg[ord[k+1].num].push_back(ord[k].num);
    }
}

void dp()
{
    sort(a+1, a+1+n);
    for(int i=1;i<=n;i++) id[a[i].num] = i;
// for(int i=0;i<g[7].size();i++) cout<<"0 0 "<<a[id[g[7][i]]].x<<" "<<a[id[g[7][i]]].y<<endl; 
    memset(d, -INF, sizeof(d));
    d[1] = 0;

    for(int i=1 , j;i<=n;i = j+1)
    {
        for(j=i;a[j+1].y==a[i].y;j++);
        lm[a[i].y] = i;   rm[a[i].y] = j;
        l[i-1] = r[j+1] = -INF;
        for(int k=i;k<=j;k++) f[k] = d[k];
        for(int k=i;k<=j;k++) l[k] = max(l[k-1] , d[k]);
        for(int k=j;k>=i;k--) r[k] = max(r[k+1] , d[k]);
        for(int k=i;k<=j;k++) d[k] = max(d[k] , max(l[k-1]+(k-i) , r[k+1]+(j-k)));

        for(int k=i;k<=j;k++)
        {
            int now = a[k].num;
            for(int x=0;x<g[now].size();x++)
            {
                int y = id[g[now][x]];
                d[y] = max(d[y] , d[k] + 1);
            }
        }
    }
}

int res;
deque<int> dq;
void print()
{
    res = 0 ;
    int w , *sup = d;
    for(int i=1;i<=n;i++) if(res <= d[i]) res = d[i] , w = i;
// for(int i=1;i<=n;i++) cout<<a[i].x<<" "<<a[i].y<<" "<<d[i]<<endl;
    cout<<res<<endl;
// cout<<a[w].x<<" "<<a[w].y<<endl;
    while(w-1)
    {
        dq.push_front(w);
        bool ok = false;
        for(int i=0;i<rg[a[w].num].size();i++)
        {
            int t = id[rg[a[w].num][i]];
            if(sup[w] == d[t] + 1)
            {
                sup = d;
                w = t;
                ok = true;
                break;
            }
        }

        if(ok) continue;
        sup = f;
        int l = lm[a[w].y] , r = rm[a[w].y];
        for(int i=l;i<w;i++) if(d[w] == f[i] + (w-l))
        {
            ok = true;
            for(int j=w-1;j>i;j--) dq.push_front(j);
            for(int j=l;j<i;j++) dq.push_front(j);
            w = i;
            break;
        }

        if(ok) continue;

        for(int i=w+1;i<=r;i++) if(d[w] == f[i] + (r-w))
        {
            ok = true;
            for(int j=w+1;j<i;j++) dq.push_front(j);
            for(int j=r;j>i;j--) dq.push_front(j);
            w = i;
            break;
        }
        assert(ok);
    }

    for(int i=0;i<dq.size();i++) printf("%d%s" , a[dq[i]].num , (i==dq.size()-1?"\n":" "));
}

int vis[maxn] , vis2[maxn] , in[maxn] , ori , S , T;

void makeNote()
{
    for(int j=n , i;j>=1;j = i-1)
    {
        for(i=j;a[i-1].y==a[j].y;i--);

        for(int k=i;k<=j;k++) 
        {
            if(d[k] == res) vis[k] = 1 , mark[k] |= 2;//, v.push_back(k);
            else 
                for(int x=0;x<g[a[k].num].size();x++)
                {
                    int y = id[g[a[k].num][x]];
                    if(vis[y] && (((mark[y]&2) && d[y] == d[k]+1) || ((mark[y]&1) && f[y] == d[k]+1)) )
                    {   
                        vis[k] = 1;
                        mark[k] |= 2;
                        in[y] ++;
                        in[k] --;
                        FLOW::addEdge(k, y, INF);
                    }
                }
        }

        set<int> dic;
        for(int k=i;k<=j;k++) vis2[k] = vis[k];
        for(int k=i;k<=j;k++)
        {
            if(dic.count(f[k]))  vis[k] = 1 , mark[k]|=1;
            if(vis2[k]) dic.insert(d[k]+k-j);
        }
        dic.clear();
        for(int k=j;k>=i;k--)
        {
            if(dic.count(f[k]))  vis[k] = 1 , mark[k]|=1;
            if(vis2[k]) dic.insert(d[k]+i-k);
        }
    }

    for(int i=1;i<=n;i++)
    if(in[i]>0) FLOW::addEdge(i, T, INF , in[i]) , ori+=in[i];
    else if(in[i]<0) FLOW::addEdge(S, i, INF , -in[i]);
}

int main(int argc, char *argv[]) {

    cin>>n;
    S = 0; T = n+2;
    for(int i=1;i<=n;i++) scanf("%d%d" , &a[i].x , &a[i].y) , a[i].num = i;
    a[++n].x = 0; a[n].y = 0; a[n].num = n;

    dpPrep();

    dp();

    print();

    FLOW::init(n+10);

    makeNote();

    cout<<ori - FLOW::maxFlow(T, S)<<endl;
    return 0;
}

你可能感兴趣的:(dp,网络流,NOI)