题目大意
给出平面直角坐标系中(n)((nleq5*10^4))个点,第(i)个点的坐标是(x_i,y_i(|x_i|leq10^9,1leq y_ileq10^9)),只有朝正上方、正左方、正右方、右上方45°、左上方45°走的路,只能在给出的点处拐弯
解决两个问题:
1.从点((0,0))出发,只能在没走到过的点处拐弯,求最多能走多少个给出的点并输出方案
2.从点((0,0))或者任意一个给出的点出发,不能朝正左方、正右方走,而且只能走被一种第1问的最优方案包含的路,求至少要走几次才能覆盖所有被一种第1问的最优路线包含了的路
题解
先预处理每个点朝正上方、正左方、正右方、右上方45°、左上方45°走遇到的第一个点
1.
把(y_i)相同的点归为同一层
设(f(i))表示如果从点(i)进入(i)所在的那一层,那么在(i)所在的层和上面的层最多能走多少给出的点
发现如果从(i)进入某一层,从(j)离开这一层,那么当(i<j)时该层最多走(j)左边所有点,当(i>j)时该层最多走(j)右边所有点,(i=j)时只会走到一个点
这是因为当(i<j)时,可以先向左走,走到(i)左边所有点,再向右走,走(i,j)之间的所有点(答案不少于(j)左边所有点)
而如果走到了(j)右边的点,就一定会走过(j),无法再从(j)离开这一层了(答案不多于(j)左边所有点)
(i>j)时同理
设(h(x))表示点(x)左上方45°的第一个点、右上方45°的第一个点、正上方的第一个点的(f)的最大值
那就有(f(i)=max(max{h(j)+(j左边的点数)mid i<j},max{h(j)+(j右边的点数)mid i>j},max{h(j)+1mid i=j}))
(f(0))就是第一问的答案
递推(f)时要记方案
2.
设(g(i))表示如果从点(i)离开(i)所在的那一层,那么离开时在(i)所在的层和下面的层最多能走多少给出的点
会发现对于一个点(i),它 左上方45°的第一个点 或 右上方45°的第一个点 或 正上方的第一个点 (j)如果满足(g(i)+f(j)=f(0))那么(i->j)就是一条出现在第一问最优方案中的路
发现这个可以是个有上下界最小流,每条路看成下界为1,上界为(infty)的边
也就是连上界为(infty)的边,算出每个点的出入度后,出>入的连(该点->超汇)且上界为(出-入)的边,出<入的连(超源->该点)且上界为(入-出)的边
通过观察题意发现这题一定有解,满流就是超源到所有点的上界之和(也是所有点到超汇的上界之和),那就可以直接用(满流时的流量-重新建图后的流量)
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define maxn 50010
#define maxm (maxn*8)
#define LL long long
#define pre(x) (!maxto[ord[x]]?tl-x+1:f[maxto[ord[x]]]+tl-x+1)
#define suf(x) (!maxto[ord[x]]?x-hd+1:f[maxto[ord[x]]]+x-hd+1)
#define now(x) (!maxto[ord[x]]?1:f[maxto[ord[x]]]+1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
return;
}
int n,xi[maxn],yi[maxn],ord[maxn],up[maxn][3],f[maxn],g[maxn],t[maxn],maxto[maxn],out[maxn],rnk[maxn],maxflow,full;
int fir[maxn],nxt[maxm],dis[maxn],v[maxm],fl[maxm],cnt,in[maxn],S,T,inf=2147483647;
bool cmpl(int x,int y){return (xi[x]+yi[x]==xi[y]+yi[y])?(yi[x]<yi[y]):(xi[x]+yi[x]<xi[y]+yi[y]);}
bool cmpr(int x,int y){return (xi[x]-yi[x]==xi[y]-yi[y])?(yi[x]<yi[y]):(xi[x]-yi[x]<xi[y]-yi[y]);}
bool cmpx(int x,int y){return (xi[x]==xi[y])?(yi[x]<yi[y]):(xi[x]<xi[y]);}
bool cmpy(int x,int y){return (yi[x]==yi[y])?(xi[x]<xi[y]):(yi[x]>yi[y]);}
void ade(int u1,int v1,int fl1)
{
v[cnt]=v1,nxt[cnt]=fir[u1],fl[cnt]=fl1,fir[u1]=cnt++;
v[cnt]=u1,nxt[cnt]=fir[v1],fl[cnt]=0,fir[v1]=cnt++;
}
int hd,tl,q[maxn];
int bfs()
{
hd=1,tl=0;
rep(i,0,T)dis[i]=inf;
dis[T]=0,q[++tl]=T;
while(hd<=tl)
{
int u=q[hd++];
view(u,k)if(fl[k^1]&&dis[v[k]]==inf)dis[v[k]]=dis[u]+1,q[++tl]=v[k];
}
return dis[S]==inf?0:1;
}
int getf(int u,int nowflow)
{
if(u==T||nowflow==0)return nowflow;
int tmp,sum=0;
view(u,k)
{
if(!nowflow)break;
if(dis[v[k]]==dis[u]-1&&fl[k]&&(tmp=getf(v[k],min(nowflow,fl[k]))))fl[k]-=tmp,fl[k^1]+=tmp,nowflow-=tmp,sum+=tmp;
}
return sum;
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read();
rep(i,1,n)xi[i]=read(),yi[i]=read(),ord[i]=i;
sort(ord,ord+n+1,cmpl);
rep(i,0,n-1){if(xi[ord[i+1]]+yi[ord[i+1]]==xi[ord[i]]+yi[ord[i]])up[ord[i]][0]=ord[i+1];}
sort(ord,ord+n+1,cmpr);
rep(i,0,n-1){if(xi[ord[i+1]]-yi[ord[i+1]]==xi[ord[i]]-yi[ord[i]])up[ord[i]][1]=ord[i+1];}
sort(ord,ord+n+1,cmpx);
rep(i,0,n-1){if(xi[ord[i+1]]==xi[ord[i]])up[ord[i]][2]=ord[i+1];}
sort(ord,ord+n+1,cmpy);int pos;
rep(i,0,n)
{
hd=i,tl=i;
while(tl+1<=n&&yi[ord[tl+1]]==yi[ord[hd]])tl++;
rep(j,hd,tl)rep(k,0,2){if(up[ord[j]][k]&&(!maxto[ord[j]]||f[up[ord[j]][k]]>f[maxto[ord[j]]]))maxto[ord[j]]=up[ord[j]][k];}
pos=-1;
rep(j,hd,tl)f[ord[j]]=now(j),out[ord[j]]=(!maxto[ord[j]])?-1:ord[j],rnk[ord[j]]=j;
rep(j,hd,tl)
{
if(pos!=-1&&pre(pos)>f[ord[j]])f[ord[j]]=pre(pos),out[ord[j]]=ord[pos];
if(pos==-1||pre(j)>pre(pos))pos=j;
}pos=-1;
dwn(j,tl,hd)
{
if(pos!=-1&&suf(pos)>f[ord[j]])f[ord[j]]=suf(pos),out[ord[j]]=ord[pos];
if(pos==-1||suf(j)>suf(pos))pos=j;
}
i=tl;
}
//rep(i,0,n)cout<<"maxto:"<<maxto[i]<<" out:"<<out[i]<<endl;
write(f[0]-1),putchar('
');
pos=maxto[0];
if(maxto[0])
{
do
{
if(rnk[out[pos]]<rnk[pos])
{
for(int i=rnk[pos];yi[ord[i]]==yi[pos];i++)write(ord[i]),putchar(' ');
for(int i=rnk[pos]-1;yi[ord[i]]==yi[pos]&&i>=rnk[out[pos]];i--)write(ord[i]),putchar(' ');
}
else if(rnk[out[pos]]>rnk[pos])
{
for(int i=rnk[pos];yi[ord[i]]==yi[pos];i--)write(ord[i]),putchar(' ');
for(int i=rnk[pos]+1;yi[ord[i]]==yi[pos]&&i<=rnk[out[pos]];i++)write(ord[i]),putchar(' ');
}
else write(pos),putchar(' ');
pos=out[pos];
if(out[pos]==-1)break;
pos=maxto[pos];
}while(pos);
putchar('
');
}
rep(i,0,n)t[i]=g[i]=-n*4;g[0]=1;
dwn(i,n,0)
{
hd=i,tl=i;
while(hd-1>=0&&yi[ord[hd-1]]==yi[ord[tl]])hd--;
pos=-1;
rep(j,hd,tl)if(t[ord[j]]>0)g[ord[j]]=t[ord[j]]+1;
rep(j,hd,tl)
{
if(pos!=-1)g[ord[j]]=max(g[ord[j]],t[ord[pos]]+j-hd+1);
if(t[ord[j]]>0&&(pos==-1||t[ord[pos]]<t[ord[j]]))pos=j;
}pos=-1;
dwn(j,tl,hd)
{
if(pos!=-1)g[ord[j]]=max(g[ord[j]],t[ord[pos]]+tl-j+1);
if(t[ord[j]]>0&&(pos==-1||t[ord[pos]]<t[ord[j]]))pos=j;
}
rep(j,hd,tl)if(g[ord[j]]>0){rep(k,0,2)if(up[ord[j]][k])t[up[ord[j]][k]]=max(t[up[ord[j]][k]],g[ord[j]]);}
i=hd;
}
S=n+1,T=n+2;
rep(i,0,n)rep(k,0,2)if(up[i][k]&&g[i]>0&&g[i]+f[up[i][k]]==f[0])in[i]--,in[up[i][k]]++,ade(i,up[i][k],inf);
rep(i,0,n)
{
if(in[i]<0)ade(i,T,-in[i]);
if(in[i]>0)ade(S,i,in[i]),full+=in[i];
}
while(bfs())maxflow+=getf(S,inf);write(full-maxflow);
return 0;
}
/*
6
-1 1
1 1
-2 2
0 8
0 9
0 10
*/
/*
4
0 1
-2 1
2 1
3 2
*/