洛谷的,有點不清楚。c++
建議去UOJ上或LOJ切了再搬運。git
luogu網絡
UOJ優化
LOJspa
老司機是一個顯然的\(dp\)。code
發現是個\(DAG\),能夠愉快的按\(y\)座標排序轉移。排序
發現五個移動很差算,那麼設\(g[i]\)表示從\(i\)點開始前往\(y\)座標比\(i\)大的點的最多到的許願樹個數,\(f[i]\)表示從\(i\)進入\(y\)座標可以最多到的許願樹個數。get
先算這一層全部的\(g\),再算\(f\)。分兩種狀況,入點在出點右邊或左邊,只要從前日後\(dp\)一次,從後往前\(dp\)一次就\(ok\)了。string
\(g\)的話維護三個桶,分別表明\(x+y\),\(x-y\),\(x\)的桶,用\(f\)轉移\(g\)。it
由於若是\(i<j,y_i==y_j\),從\(i\)點進\(j\)點出能夠先往左走,再往右走到\(j\)離開,因此算的時候貢獻是\(y\)座標爲\(y_i\)的點的個數減去\(j\)和它右邊的點的個數,那麼咱們能夠一開始減掉,最後算答案的時候加上\(y\)座標爲\(y_i\)的點的個數。這顯然是個前綴或後綴\(max\)的優化\(dp\)。
那麼咱們獲得了\(20\ pts\ QAQ\)。
\(40\)分的話也好作,\(dfs\)一條路出來,你怎麼轉移的就倒過來怎麼找路徑,具體能夠看代碼。
\(100\)分不難,按\(40\)分的思路去找全部的邊,只是不\(dfs\)而是遍歷每一個可能出現的點。
而後就是個很裸的上下界最小流了。
聽\(litble\)說直接寫會\(TLE\),因此我就沒寫最裸的,加了個優化。
由於你確定有解,而且\(S\)和\(T\)到每一個點都有\(inf\)的邊,因此咱們無論它們,直接建超級源匯連原圖,跑出來最大流就是圖本生能夠減小的流量。
減掉就\(ok\)了。
不算網絡流模板這道題還挺短的\(QAQ\)。
#include<map> #include<algorithm> #include<queue> #include<cstdio> #include<cctype> #include<cstring> #define gt getchar() #define ll long long #define Set(p,v) memset(p,v,sizeof(p)) #define Cpy(p,v) memcpy(p,v,sizeof(p)) inline int in() { int k=0,p=1;char ch=gt; while(!isdigit(ch)&&ch!='-')ch=gt; if(ch=='-')p=0,ch=gt; while(isdigit(ch))k=k*10+ch-'0',ch=gt; return p?k:-k; } inline int min(const int &a,const int &b){return a<b?a:b;} inline int max(const int &a,const int &b){return a>b?a:b;} const int inf=0x7fffffff; class Graph { private: static const int N=400005,M=1000005; int s,t; int dis[N]; int pre[N],pr[N],o[N],cur[N]; int head[N],nxt[M],to[M],cap[M];double w[M]; public: int n,cnt; inline void init(int nn,int ss,int tt){n=nn,s=ss,t=tt;cnt=-1;Set(head,-1);} inline void add_Edge(int u,int v,int cc,int ww){to[++cnt]=v,cap[cnt]=cc,w[cnt]=ww,nxt[cnt]=head[u],head[u]=cnt;} inline void add(int u,int v,int cc,int ww=0){add_Edge(u,v,cc,ww),add_Edge(v,u,0,-ww);} int dfs(int u,int dist) { if(u==t)return dist; for(int &i=cur[u];~i;i=nxt[i]) { if(dis[to[i]]==dis[u]+1&&cap[i]!=0) { int d=dfs(to[i],min(dist,cap[i])); if(d>0){cap[i]-=d;cap[i^1]+=d;return d;} } } return 0; } int bfs() { std::queue<int>Q;Set(dis,0); Q.push(s);dis[s]=1; while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=head[u];~i;i=nxt[i]) { if(cap[i]>0&&dis[to[i]]==0) { dis[to[i]]=dis[u]+1; Q.push(to[i]); } } } return dis[t]>0; } int dinic() { int res=0,d; while(bfs()){Cpy(cur,head);while((d=dfs(s,inf)))res+=d;} return res; } int spfa() { //實數流的時候務必用for給dis賦值 std::queue<int>Q;Set(dis,0x3f);Set(pr,0);Set(o,0);Set(pre,0); dis[s]=0;Q.push(s);o[s]=1; while(!Q.empty()) { int u=Q.front();Q.pop();o[u]=0; for(int i=head[u];~i;i=nxt[i]) if(cap[i]>0&&dis[to[i]]>dis[u]+w[i]) { dis[to[i]]=dis[u]+w[i]; pr[to[i]]=i;pre[to[i]]=u; if(!o[to[i]])o[to[i]]=1,Q.push(to[i]); } } return pre[t]!=0; } void fyl(int &ans,int &hh) { ans=hh=0; while(spfa()) { int d=inf; for(int i=t;i!=s;i=pre[i])d=min(d,cap[pr[i]]);hh+=dis[t]*d;ans+=d; for(int i=t;i!=s;i=pre[i])cap[pr[i]]-=d,cap[pr[i]^1]+=d; } } int fyl() { int hh=0; while(spfa()) { int d=inf; for(int i=t;i!=s;i=pre[i])d=min(d,cap[pr[i]]);hh+=dis[t]*d; for(int i=t;i!=s;i=pre[i])cap[pr[i]]-=d,cap[pr[i]^1]+=d; } return hh; } }cx; typedef std::pair<int,int> P; #define mk std::make_pair #define fr first #define sc second const int N=50005; int n,tot;P E[N*20]; struct point{int x,y,id;}a[N]; inline bool cmpx(point a,point b){return a.x==b.x?a.y<b.y:a.x<b.x;} inline bool cmpy(point a,point b){return a.y==b.y?a.x<b.x:a.y<b.y;} inline bool cmpi(point a,point b){return a.id<b.id;} inline void cmax(int &x,int y,int *a,int &c,int b){if(x<y)x=y,a[(c=1)-1]=b;else if(x==y)a[c++]=b;} inline void cmax(int &x,int y){if(x<y)x=y;} inline void Push(int x,int y){E[++tot]=mk(x,y);} namespace w1 { using std::map; map<int,int>t1,t2,t3,mp[N]; int f[N],g[N],pre[N][3],L[N],R[N],TT,o[N],cnt[N]; inline int calc(int u,int k) { if(u==k)return g[k]; if(u<k)return g[k]+k-L[k]; else return g[k]+R[k]-k; } void dfs(int val,int u)//求一組最優方案 { if(u==-1)return; if(u!=1)printf("%d ",a[u].id); int l=L[u],r=R[u]; for(int i=l;i<=r;++i) if(calc(u,i)==val) { if(u==i)return dfs(g[u]-1,pre[u][0]); if(u<i)for(int j=u-1;j>=l;--j)printf("%d ",a[j].id); else for(int j=u+1;j<=r;++j)printf("%d ",a[j].id); if(u<i)for(int j=u+1;j<=i;++j)printf("%d ",a[j].id); else for(int j=u-1;j>=i;--j)printf("%d ",a[j].id); return dfs(g[i]-1,pre[i][0]); } } void Dfs(int val,int u)//求全部邊 { if(u==-1||o[u])return; int l=L[u],r=R[u];o[u]=1; for(int i=l;i<=r;++i) if(calc(u,i)==val) for(int k=0;k<cnt[i];++k) if(pre[i][k]&&pre[i][k]!=-1) { if(mp[i].find(k)==mp[i].end())Push(i,pre[i][k]),mp[i][k]=1; if(!o[pre[i][k]])Dfs(g[i]-1,pre[i][k]); } } void solve() { a[++n]=(point){0,0,0};std::sort(a+1,a+n+1,cmpy); for(int i=n,j;i>=1;i=j-1) { for(j=i;j>1&&a[j-1].y==a[i].y;--j); for(int k=j;k<=i;++k)L[k]=j,R[k]=i; for(int k=j;k<=i;++k) { int x=a[k].x,y=a[k].y;g[k]=1;pre[k][cnt[k]=0]=-1; if(t1.find(x+y)!=t1.end())cmax(g[k],f[t1[x+y]]+1,pre[k],cnt[k],t1[x+y]); if(t2.find(x-y)!=t2.end())cmax(g[k],f[t2[x-y]]+1,pre[k],cnt[k],t2[x-y]); if(t3.find( x )!=t3.end())cmax(g[k],f[t3[ x ]]+1,pre[k],cnt[k],t3[ x ]); t1[x+y]=t2[x-y]=t3[x]=k; } for(int k=j,mx=-1e9;k<=i;++k) cmax(f[k],g[k]),cmax(f[k],mx+i-j),cmax(mx,g[k]-k+j); for(int k=i,mx=-1e9;k>=j;--k) cmax(f[k],g[k]),cmax(f[k],mx+i-j),cmax(mx,g[k]-i+k); } printf("%d\n",f[1]-1);dfs(f[1],1);puts("");Dfs(f[1],1); } } namespace w2 { int du[N]; void solve() { int t=n+1,s=0,ans=0;cx.init(t+1,s,t); for(int i=1;i<=tot;++i) --du[E[i].fr],++du[E[i].sc],cx.add(E[i].fr,E[i].sc,inf); for(int i=1;i<=n;++i) if(du[i]>0)cx.add(s,i,du[i]),ans+=du[i]; else if(du[i]<0)cx.add(i,t,-du[i]); printf("%d\n",ans-cx.dinic()); } } int main() { n=in(); for(int i=1;i<=n;++i)a[i].x=in(),a[i].y=in(),a[i].id=i; w1::solve();w2::solve(); return 0; }