膜拜大神题解: http://blog.csdn.net/popoqqq/article/details/47402925
http://www.cnblogs.com/maijing/p/4689740.html
不管怎么说,参观了很多大神的代码,还是把老司机给A掉了
第一二问 DP 但是细节很多 码出来的神犇很强 自己代码能力太差
然后之后还得来个DP 与第一遍方向相反 就是倒着走 用来判断是不是最长链上的一条边 %%PoPoQQQ
之后就是有下界的最小流
”
求有上下界的最小流的做法是:先不连S到T,求superS到superT的最大流。然后再连S到T一条容量为INF的边,再求supperS到superT的最大流,如果满流,则第二次增广的就是原图的最小流,其实就是满流减去第一次做的最大流。否则无解。
但这道题是肯定有解的,所以不用第二次增广,直接满流-第一次增广得到的最大流。
“ ——来自maijing
其他感想:
出这道题的神犇也很强!要是有点条件的变动,那么似乎就会很难做,比如只保留水平压痕。一道道题下来,真的想在OI这条路上走得更远。
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> using namespace std; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } int n; struct Point{ int x,y,idx; bool operator < (const Point &B) const{ return y==B.y?x<B.x:y<B.y; } }P[50005]; int Ans,Cnt,Minc; int f[50005],h[50005],mx[50005]; int g[50005],pre[50005]; int pnt,lst[50005]; inline void load(int x,int y) { int t; if (x<y) { for (t=y;t>x;t--) lst[++pnt]=t; while (P[t].y==P[t-1].y) t--; for (;t<=x;t++) lst[++pnt]=t; } else { for (t=y;t<x;t++) lst[++pnt]=t; while (P[t].y==P[t+1].y) t++; for (;t>=x;t--) lst[++pnt]=t; } } inline void Print() { if (!Ans) { printf("\n"); return; } int t=0; for (int i=1;i<=n && !t;i++) if (f[i]==Ans) t=i; for (int i=t;i;) if (pre[i]) load(pre[i],i),i=g[pre[i]]; else lst[++pnt]=i,i=g[i]; for (int i=pnt;i>1;i--) printf("%d ",P[lst[i]].idx); printf("%d\n",P[lst[1]].idx); } map<int,int> m1,m2,m3; inline void DP() { int pos; m1.clear(); m2.clear(); m3.clear(); m1[0]=m2[0]=m3[0]=0; for (int i=1;i<=n;i++) f[i]=-1<<30; for (int i=1,t;i<=n;i=t+1) { t=i; while (t+1<=n && P[t].y==P[t+1].y) t++; for (int j=i;j<=t;j++) { if (m1.find(P[j].x+P[j].y)!=m1.end()) { pos=m1[P[j].x+P[j].y]; if (f[j]<f[pos]+1) f[j]=f[pos]+1,g[j]=pos; } m1[P[j].x+P[j].y]=j; if (m2.find(P[j].x-P[j].y)!=m2.end()) { pos=m2[P[j].x-P[j].y]; if (f[j]<f[pos]+1) f[j]=f[pos]+1,g[j]=pos; } m2[P[j].x-P[j].y]=j; if (m3.find(P[j].x)!=m3.end()) { pos=m3[P[j].x]; if (f[j]<f[pos]+1) f[j]=f[pos]+1,g[j]=pos; } m3[P[j].x]=j; } for (int j=i;j<=t;j++) mx[j]=f[j]; pos=-1; for (int j=i+1;j<=t;j++) { if (pos==-1 || f[j-1]>f[pos]) pos=j-1; if (mx[j]<f[pos]+j-i) mx[j]=f[pos]+j-i,pre[j]=pos; } pos=-1; for (int j=t-1;j>=i;j--) { if (pos==-1 || f[j+1]>f[pos]) pos=j+1; if (mx[j]<f[pos]+t-j) mx[j]=f[pos]+t-j,pre[j]=pos; } for (int j=i;j<=t;j++) { if (mx[j]>f[j]) f[j]=mx[j]; else pre[j]=0; Ans=max(Ans,f[j]); } } printf("%d\n",Ans); Print(); } inline void EXDP() { int pos; for (int i=1;i<=n;i++) if (f[i]==Ans) h[i]=1; else h[i]=-1<<30; m1.clear(); m2.clear(); m3.clear(); for (int i=n,t;i;i=t-1) { t=i; while (t-1 && P[t].y==P[t-1].y) t--; for (int j=i;j>=t;j--) { if (m1.find(P[j].x+P[j].y)!=m1.end()) { pos=m1[P[j].x+P[j].y]; if (h[j]<h[pos]+1) h[j]=h[pos]+1; } m1[P[j].x+P[j].y]=j; if (m2.find(P[j].x-P[j].y)!=m2.end()) { pos=m2[P[j].x-P[j].y]; if (h[j]<h[pos]+1) h[j]=h[pos]+1; } m2[P[j].x-P[j].y]=j; if (m3.find(P[j].x)!=m3.end()) { pos=m3[P[j].x]; if (h[j]<h[pos]+1) h[j]=h[pos]+1; } m3[P[j].x]=j; } for (int j=i;j>=t;j--) mx[j]=h[j]; pos=-1; for (int j=t+1;j<=i;j++) { if (pos==-1 || h[j-1]+i-j+1>h[pos]+i-pos) pos=j-1; if (h[pos]+i-pos>mx[j]) mx[j]=h[pos]+i-pos; } pos=-1; for (int j=i-1;j>=t;j--) { if (pos==-1 || h[j+1]+j+1-t>h[pos]+pos-t) pos=j+1; if (h[pos]+pos-t>mx[j]) mx[j]=h[pos]+pos-t; } for (int j=i;j>=t;j--) if (mx[j]>h[j]) h[j]=mx[j]; } } namespace DINIC{ #define oo 1<<30 #define V G[p].v #define cl(x) memset(x,0,sizeof(x)) #define M 1000000+5 #define N 60000+5 struct edge{ int u,v,f; int next; }; edge G[M]; int head[N],num=1; inline void add(int u,int v,int f,int p){ G[p].u=u; G[p].v=v; G[p].f=f; G[p].next=head[u]; head[u]=p; } inline void link(int u,int v,int f){ add(u,v,f,num+=2); add(v,u,0,num^1); } int S,T; int Que[N],l,r; int dis[N]; inline bool bfs(){ int u; memset(dis,-1,sizeof(dis)); cl(Que); l=r=-1; dis[S]=1; Que[++r]=S; while (l<r) { u=Que[++l]; for (int p=head[u];p;p=G[p].next) if (G[p].f && dis[V]==-1) { dis[V]=dis[u]+1; Que[++r]=V; if (V==T) return true; } } return false; } int minimum; int cur[N]; inline bool dfs(int u,int mini){ if (u==T) { minimum=mini; return true; } for (int p=cur[u];p;p=G[p].next) { cur[u]=p; if (G[p].f && dis[V]==dis[u]+1 && dfs(V,min(mini,G[p].f))) { G[p].f-=minimum; G[p^1].f+=minimum; return true; } } dis[u]=-1; return false; } inline int Dinic(){ int ret=0; while (bfs()) { memcpy(cur,head,sizeof(cur)); while (dfs(S,oo)) ret+=minimum; } return ret; } inline void clear(){ cl(G); cl(head); num=1; } } int du[50015]; inline void Solve() { using namespace DINIC; int s=n+1,t=n+2,pos; S=n+3; T=n+4; m1.clear(); m2.clear(); m3.clear(); for (int i=n;i>=0;i--) { if (m1.find(P[i].x+P[i].y)!=m1.end()) { pos=m1[P[i].x+P[i].y]; if (f[i]+h[pos]==Ans) link(i,pos,oo),du[i]--,du[pos]++; } m1[P[i].x+P[i].y]=i; if (m2.find(P[i].x-P[i].y)!=m2.end()) { pos=m2[P[i].x-P[i].y]; if (f[i]+h[pos]==Ans) link(i,pos,oo),du[i]--,du[pos]++; } m2[P[i].x-P[i].y]=i; if (m3.find(P[i].x)!=m3.end()) { pos=m3[P[i].x]; if (f[i]+h[pos]==Ans) link(i,pos,oo),du[i]--,du[pos]++; } m3[P[i].x]=i; } for (int i=0;i<=n;i++) link(s,i,oo),link(i,t,oo); for (int i=0;i<=n;i++) if (du[i]>0) Cnt+=du[i],link(S,i,du[i]); else link(i,T,-du[i]); Minc=Dinic(); Minc=Cnt-Minc; printf("%d\n",Minc); } int main() { freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); for (int i=1;i<=n;i++) read(P[i].x),read(P[i].y),P[i].idx=i; sort(P+1,P+n+1); DP(); EXDP(); Solve(); return 0; }