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就是
这里写图片描述
考虑一直只走顶点,这样对于线段两侧的点,即非顶点的点,可以通过一次拐弯走到,所以只有最后一条线段会影响答案,特判即可。
对于一个出发点的两条路径,如果某个时刻开始不再交错,就可以如上调整让答案变优。
特判超多。。O(nm)

0 0
原创粉丝点击