GYM100608 J

版权声明:题解在下面 (゜-゜) https://blog.csdn.net/u010600261/article/details/70050749

题意:
在一个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 2100
using 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)

展开阅读全文

没有更多推荐了,返回首页