感觉这是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;
}