GYM100608 J
来源:互联网 发布:云数据库 编辑:程序博客网 时间:2024/05/30 05:41
题意:
在一个n*m的四联通网格中有一个凸的联通块。当一个联通块与每行每列的交都是线段时,我们称它是凸的。对于两个点x和y,J(x,y)表示从x到y最少拐几个弯。询问max(J(x,y))。
n,m<=2000
#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#define N 2100using namespace std;struct node{ int x,y; friend bool operator ==(node x,node y) { return (x.x==y.x)&&(x.y==y.y); }}a[2*N],b[2*N];char s[N][N];int n,m,l[N],r[N],u[N],d[N],al,bl,ans;int mrd(node a,node b){ int x1=a.x,y1=a.y,x2=b.x,y2=b.y; if(x1==x2) { for(int i=y1;i<=y2;i++) if(d[i]>x1) return 1; return 0; } else { for(int i=x1;i<=x2;i++) if(r[i]>y1) return 1; return 0; }}void rd(int x,int y){ al=1;a[1]=(node){x,y}; while(1) { x=a[al].x;y=a[al].y; if(al%2) {if(r[x]==y) return;a[++al]=(node){x,r[x]};} else {if(d[y]==x) return;a[++al]=(node){d[y],y};} }}void dr(int x,int y){ bl=1;b[1]=(node){x,y}; while(1) { x=b[bl].x;y=b[bl].y; if(bl%2==0) {if(r[x]==y) return;b[++bl]=(node){x,r[x]};} else {if(d[y]==x) return;b[++bl]=(node){d[y],y};} }}void make_rd(int x,int y){ int t=0; rd(x,y);dr(x,y); if(al==1 || bl==1) { if(al==1 && bl==1) t=0; else if(al==1) t=bl-2+mrd(b[bl-1],b[bl]); else t=al-2+mrd(a[al-1],a[al]); } else if(a[al]==b[bl]) { if(al==bl) t=al-2; else { if(al>bl) t=bl-2+mrd(a[al-1],a[al]); else t=al-2+mrd(b[bl-1],b[bl]); } } else { int t1=al-2,t2=bl-2,p=al+1; for(int i=2;i<=al && i-1<=bl;i++) if(a[i].x<b[i-1].x || a[i].y<b[i-1].y) {p=i;break;} if(p<al) t1--; else if(p>al) { if(a[al].y==a[al-1].y) t1+=mrd((node){b[al-1].x+1,a[al].y},a[al]); else t1+=mrd((node){a[al].x,b[al-1].y+1},a[al]); } p=bl+1; for(int i=2;i<=bl && i-1<=al;i++) if(b[i].x<a[i-1].x || b[i].y<a[i-1].y) {p=i;break;} if(p<bl) t2--; else if(p>bl) { if(b[bl].y==b[bl-1].y) t2+=mrd((node){a[bl-1].x+1,b[bl].y},b[bl]); else t2+=mrd((node){b[bl].x,a[bl-1].y+1},b[bl]); } t=max(t1,t2); } ans=max(ans,t);}int mru(node a,node b){ int x1=a.x,y1=a.y,x2=b.x,y2=b.y; if(x1==x2) { for(int i=y1;i<=y2;i++) if(u[i]<x1) return 1; return 0; } else { for(int i=x2;i<=x1;i++) if(r[i]>y1) return 1; return 0; }}void ru(int x,int y){ al=1;a[1]=(node){x,y}; while(1) { x=a[al].x;y=a[al].y; if(al%2) {if(r[x]==y) return;a[++al]=(node){x,r[x]};} else {if(u[y]==x) return;a[++al]=(node){u[y],y};} }}void ur(int x,int y){ bl=1;b[1]=(node){x,y}; while(1) { x=b[bl].x;y=b[bl].y; if(bl%2==0) {if(r[x]==y) return;b[++bl]=(node){x,r[x]};} else {if(u[y]==x) return;b[++bl]=(node){u[y],y};} }}void make_ru(int x,int y){ int t=0; ru(x,y);ur(x,y); if(al==1 || bl==1) { if(al==1 && bl==1) t=0; else if(al==1) t=bl-2+mru(b[bl-1],b[bl]); else t=al-2+mru(a[al-1],a[al]); } else if(a[al]==b[bl]) { if(al==bl) t=al-2; else { if(al>bl) t=bl-2+mru(a[al-1],a[al]); else t=al-2+mru(b[bl-1],b[bl]); } } else { int t1=al-2,t2=bl-2,p=al+1; for(int i=2;i<=al && i-1<=bl;i++) if(a[i].x>b[i-1].x || a[i].y<b[i-1].y) {p=i;break;} if(p<al) t1--; else if(p>al) { if(a[al].y==a[al-1].y) t1+=mru((node){b[al-1].x-1,a[al].y},a[al]); else t1+=mru((node){a[al].x,b[al-1].y+1},a[al]); } p=bl+1; for(int i=2;i<=bl && i-1<=al;i++) if(b[i].x>a[i-1].x || b[i].y<a[i-1].y) {p=i;break;} if(p<bl) t2--; else if(p>bl) { if(b[bl].y==b[bl-1].y) t2+=mru((node){a[bl-1].x-1,b[bl].y},b[bl]); else t2+=mru((node){b[bl].x,a[bl-1].y+1},b[bl]); } t=max(t1,t2); } ans=max(ans,t);}int main(){ freopen("jinxiety.in","r",stdin); freopen("jinxiety.out","w",stdout); int z=0; while(1) { z++; scanf("%d%d",&n,&m); if(n==0) break; for(int i=1;i<=n;i++) scanf("%s",s[i]+1); /*if(z==3112) { for(int i=1;i<=n;i++) printf("%s\n",s[i]+1); return 0; }*/ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(s[i][j]=='.') continue; if(l[i]==0) l[i]=j; r[i]=j; } for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { if(s[j][i]=='.') continue; if(u[i]==0) u[i]=j; d[i]=j; } ans=0; for(int i=1;i<=n;i++) { if(l[i]==0) continue; make_rd(i,l[i]); make_ru(i,l[i]); int oo=1; } //if(z<=2) printf("%d\n",ans); for(int i=1;i<=n;i++) l[i]=r[i]=0; for(int i=1;i<=m;i++) u[i]=d[i]=0; } return 0;}
题解:
显然可以只考虑右上和右下两种走法,并以每行的左端点为起点。
对于右下的情况,核心的idea就是
考虑一直只走顶点,这样对于线段两侧的点,即非顶点的点,可以通过一次拐弯走到,所以只有最后一条线段会影响答案,特判即可。
对于一个出发点的两条路径,如果某个时刻开始不再交错,就可以如上调整让答案变优。
特判超多。。
0 0
- GYM100608 J
- J
- j
- j
- J#
- J
- J
- J
- J
- j
- J
- J
- J
- J
- J
- J
- J
- J
- map,multimap,set,multiset
- 18-TCP 协议(迟到的 ACK—— Linux)
- POJ
- web项目,运行时不抛异常,调试时出现InvocationTargetException
- Python-Pandas 学习 数据中对时间的操作
- GYM100608 J
- LeetCode-135. Candy (JAVA)根据等级分糖果
- 模仿iOS7 task switcher的卡片动画
- java中next与nextLine用法区别
- ETL工具比较(Informatica ,SSIS,Kettle )
- java分页 (spring+springmvc+hibernate)
- 遍历map的几种方式
- ztree组件使用--判断选中节点的根节点
- iOS 基于GCDAsyncSocket快速开发Socket通信