由于每行点的个数不超过1000,所以行内DP可以使用$O(n^2)$算法。

先找到每个点所能直接到达的所有点(x,y,x+y或x-y相同),用排序实现。

第一问:以行为阶段,对于每行,暴力枚举最有路径在这行上的起点和终点,g[x]记录当这行的最优路径以x为起点时,终点应在什么位置,f[x]记录走到x且这一行以x为起点,之后最多还能走到多少个点。

第二问:由于当一行的起点和终点都确定后,决策也是确定的,故只需要沿着DFS一遍即可得到最优路径。

第三问:先考虑怎么找到所有可能在最优路径上的边,同样暴力枚举每行的起点和终点即可,注意处理(0,0)的情况。找到符合要求的边后,问题就是用最少的路径数覆盖这些边,使用有上下界的最小流求解。

 #include<map>
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=,M=,inf=;
bool va[N],vb[N];
int n,mx,cnt=,s0,ss,tt,S,T,d[N],f[N],h[N],dis[N],idx[N],q[N],cur[N],a[N],mp[N][];
int Lst[N],Nxt[N],pre[N],suf[N],premx[N],sufmx[N],to[M],fl[M],nxt[M],Do[N],Do2[N];
struct P{ int x,y; }p[N]; bool cmp1(int a,int b){ return (p[a].y==p[b].y) ? p[a].x<p[b].x : p[a].y<p[b].y; }
bool cmp2(int a,int b){ return (p[a].x==p[b].x) ? p[a].y<p[b].y : p[a].x<p[b].x; }
bool cmp3(int a,int b){ return (p[a].x-p[a].y==p[b].x-p[b].y) ? p[a].y<p[b].y : p[a].x-p[a].y<p[b].x-p[b].y; }
bool cmp4(int a,int b){ return (p[a].x+p[a].y==p[b].x+p[b].y) ? p[a].y<p[b].y : p[a].x+p[a].y<p[b].x+p[b].y; }
bool cmp5(int a,int b){ return (p[a].y==p[b].y) ? p[a].x<p[b].x : p[a].y>p[b].y; } inline void add(int u,int v,int w){
to[++cnt]=v; fl[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt;
to[++cnt]=u; fl[cnt]=; nxt[cnt]=h[v]; h[v]=cnt;
} void work(int u,int v,int low,int high){ add(u,v,high-low); d[u]-=low; d[v]+=low; } bool bfs(){
rep(i,,n+) dis[i]=; dis[S]=; q[]=S;
for (int st=,ed=; st<ed; ){
int x=q[++st];
For(i,x) if (fl[i] && !dis[k=to[i]]) dis[k]=dis[x]+,q[++ed]=k;
}
return dis[T];
} int dfs(int x,int lim){
if (x==T) return lim;
int c=;
for (int i=cur[x],k; i; i=nxt[i])
if (fl[i] && dis[k=to[i]]==dis[x]+){
int t=dfs(k,min(lim-c,fl[i]));
c+=t; fl[i]-=t; fl[i^]+=t;
if (fl[i]) cur[x]=i;
if (c==lim) return lim;
}
if (!c) dis[x]=-;
return c;
} int dinic(){
int res=;
while (bfs()){
rep(i,,n+) cur[i]=h[i];
res+=dfs(S,inf);
}
return res;
} void Print(int x){
if (!x) return;
printf("%d ",x);
if (Do[x]==) { Print(mp[x][Do2[x]]); return; }
if (idx[x]>idx[Do[x]]){
int t=Do[x];
for (int i=Nxt[x]; i; i=Nxt[i]) printf("%d ",i);
for (x=Lst[x]; x!=t; x=Lst[x]) printf("%d ",x);
printf("%d ",t); Print(mp[t][Do2[t]]); return;
}
if (idx[x]<idx[Do[x]]){
int t=Do[x];
for (int i=Lst[x]; i; i=Lst[i]) printf("%d ",i);
for (x=Nxt[x]; x!=t; x=Nxt[x]) printf("%d ",x);
printf("%d ",t); Print(mp[t][Do2[t]]); return;
}
} void solve1(){
rep(i,,n) a[i]=i;
sort(a+,a+n+,cmp1);
rep(i,,n) if (p[a[i-]].y==p[a[i]].y) Lst[a[i]]=a[i-],Nxt[a[i-]]=a[i];
sort(a+,a+n+,cmp2);
rep(i,,n) if (p[a[i-]].x==p[a[i]].x) mp[a[i-]][]=a[i];
sort(a+,a+n+,cmp3);
rep(i,,n) if (p[a[i-]].x-p[a[i-]].y==p[a[i]].x-p[a[i]].y) mp[a[i-]][]=a[i];
sort(a+,a+n+,cmp4);
rep(i,,n) if (p[a[i-]].x+p[a[i-]].y==p[a[i]].x+p[a[i]].y) mp[a[i-]][]=a[i];
sort(a+,a+n+,cmp5);
rep(i,,n) idx[a[i]]=i;
} void W(int x){
rep(i,,) if (mp[x][i]){
int to=mp[x][i];
if (f[to]+>f[x]) Do2[x]=i,f[x]=f[to]+;
}
} int calc(int x,int y){
return (idx[x]<idx[y]) ? pre[y]+f[mp[y][Do2[y]]] : suf[y]+f[mp[y][Do2[y]]];
} bool jud(P &p){ return p.x== || p.x==p.y || p.x==-p.y; } void solve2(){
rep(k,,n) if (p[a[k]].y!=p[a[k-]].y) pre[a[k]]=; else pre[a[k]]=pre[a[k-]]+;
for (int k=n; k; k--) if (p[a[k]].y!=p[a[k+]].y) suf[a[k]]=; else suf[a[k]]=suf[a[k+]]+;
rep(k,,n) if (p[a[k]].y!=p[a[k-]].y){
for (int x=a[k]; x; x=Nxt[x]) f[x]=,W(x);
for (int x=a[k]; x; x=Nxt[x])
for (int y=a[k]; y; y=Nxt[y])
if (y!=x && calc(x,y)>f[x]) f[x]=calc(x,y),Do[x]=y;
}
rep(i,,n) if (jud(p[i])) mx=max(mx,f[i]);
printf("%d\n",mx);
rep(i,,n) if (f[i]==mx && jud(p[i])) { Print(i); break; }
puts("");
} int solve3(){
rep(i,,n) if (f[i]==mx && jud(p[i])) work(s0,i,,inf),va[i]=;
for (int i=n; i; i--) if (p[a[i]].y!=p[a[i+]].y){
for (int x=a[i]; x; x=Lst[x]) if (va[x]){
if (f[mp[x][Do2[x]]]+==f[x]) vb[x]=;
for (int y=a[i]; y; y=Lst[y]) if (y!=x && calc(x,y)==f[x]) vb[y]=;
}
for (int x=a[i]; x; x=Lst[x])
if (vb[x]) rep(j,,) if (mp[x][j] && f[mp[x][j]]==f[mp[x][Do2[x]]])
va[mp[x][j]]=,work(x,mp[x][j],,inf);
}
rep(i,,n+) work(ss,i,,inf),work(i,tt,,inf);
rep(i,,n+) if (d[i]>) add(S,i,d[i]); else add(i,T,-d[i]);
add(tt,ss,inf); dinic(); S=tt; T=ss; return inf-dinic();
} int main(){
freopen("driver.in","r",stdin);
freopen("driver.out","w",stdout);
scanf("%d",&n); s0=n+; ss=n+; tt=n+; S=n+; T=n+;
rep(i,,n) scanf("%d%d",&p[i].x,&p[i].y);
solve1(); solve2(); printf("%d\n",solve3());
return ;
}

最新文章

  1. Werewolf流程分析
  2. WPF学习之路(九)导航和页面(续)
  3. git回滚
  4. 为UITextView添加与UITextField一样的边框——UITextField默认边框颜色、宽度、圆角
  5. 解决laravel中环境配置不起作用的方法
  6. Failed to load unit &#39;PATM&#39; (VERR_SSM_FIELD_NOT_CONSECUTIVE)
  7. Java 内存区域和GC机制--备用
  8. Day5 双层装饰器、字符串格式化、生成器、迭代器、递归
  9. CTime,Systemtime的比较还有转换成日期格式。
  10. HashMap工作原理
  11. QtWebkit中如何将网页内容转为图片
  12. Python[小甲鱼007了不起的分支和循环]
  13. Linux运维第二课----Linux发展史、环境准备
  14. k8s架构分析(二)--技术流ken
  15. Node-SASS安装 scss
  16. Hadoop记录-hadoop2.x常用端口及定义方法
  17. Linux进程优先级系统——设置实时进程优先级
  18. module模块和包
  19. Spark 集群搭建
  20. 【Spring】spring的7个模块

热门文章

  1. 【ALB学习笔记】基于多线程方式的串行通信接口数据接收案例
  2. MSSQL数据库 事务隔离级别
  3. js 合并多个对象 Object.assign
  4. bugku逗号过滤注入
  5. SD卡 模拟SPI总线控制流程
  6. 【VI Script】你不知道的脚本编程
  7. StringBuilder类的作用,以及与String类的相互转换
  8. jps命令学习
  9. mysql:视图、触发器、事务、存储、函数、流程控制
  10. Jmeter----读取excel表中的数据