ACM/ICPC 2012金华regional现场赛C题 hdu4444 离散化、最短路

2012/12/31 修正。
最主要的修改了拐角点无法通过的问题,将格子分为8种情况特判。例如某个格子的左下,右下,左上的格子都是黑格,那么这个拐角点就是"L"形状的,我设它为状态5。那么在这个格子上,只有上方和右方可以进入格子,而当从右方进入格子时只有上方能离开格子,从上方进入时只有右方能离开。

这些判定通过两个函数check3(格子状态,进入方向)和check2(格子状态,进入方向,离开方向)来判定。

另外小修改了离散化的坐标,将起点终点的坐标也加入离散,这样就可以不用特判ans=0的情况了。

修改后的程序能够通过这组数据了:
0 -1 2 1
3
-1 0 0 1
0 1 1 2
1 -2 3 0
正确答案为1。经过拐角点。
修改后的程序能够在HDUAC了。不过用时还是有点多。。
修正代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define NN 400
#define INF 100000000


int stx,sty,edx,edy;
int n,tx,ty,sx[NN],sy[NN],a,b,c,d,ttx,tty,i,ans,flag;
int dis[NN][NN][5],inq[NN][NN][5],g[NN][NN];
int dx[]={0,1,0,-1};//上 右 下 左 
int dy[]={1,0,-1,0};

struct point {
    int x,y;
    void init(int _x,int _y){x=_x;y=_y;};
}bu[NN][10];
  

int bsch1(int val,int v[],int l,int r){//二分寻找离散后的位置,其实暴力也可以吧
    int mid;
    while(l<=r){
       mid=(l+r)>>1;
       if (v[mid]==val) return mid;
       if (v[mid]<val) l=mid+1;
       else r=mid-1;
    }
    //while(1);
}

inline int check2(int gsta,int ud,int vd){
    if (gsta==0) return 1;
    else if (gsta==2){
        if (ud==1&&vd==0) return 1;
        if (ud==2&&vd==3) return 1;
    }
    else if (gsta==3){
        if (ud==0&&vd==1) return 1;
        if (ud==3&&vd==2) return 1;
    }
    else if (gsta==4){
        if (ud==1&&vd==0) return 1;
        if (ud==2&&vd==3) return 1;
        if (ud==0&&vd==1) return 1;
        if (ud==3&&vd==2) return 1;
    }
    else if (gsta==5){
        if (ud==2&&vd==1) return 1;
        if (ud==3&&vd==0) return 1;
    }
    else if (gsta==6){
        if (ud==1&&vd==2) return 1;
        if (ud==0&&vd==3) return 1;
    }
    else if (gsta==7){
        if (ud==2&&vd==1) return 1;
        if (ud==3&&vd==0) return 1;
        if (ud==1&&vd==2) return 1;
        if (ud==0&&vd==3) return 1;
    }
    return 0;
}

inline int check3(int gsta,int ud){
    if (gsta==0) return 1;
    else if (gsta==2){ if (ud==1||ud==2) return 1; }
    else if (gsta==3){ if (ud==0||ud==3) return 1; }
    else if (gsta==4){ return 1; }
    else if (gsta==5){ if (ud==2||ud==3) return 1; }
    else if (gsta==6){ if (ud==1||ud==0) return 1; }
    else if (gsta==7){ return 1; }
    return 0;
}
           

inline void check(int i,int j){ //检查格子是否可走
     if (g[i-1][j]&&g[i+1][j]) g[i][j]=1;
     if (g[i][j-1]&&g[i][j+1]) g[i][j]=1;
     if (g[i-1][j-1]&&g[i+1][j+1]){
        if (g[i+1][j-1]&&g[i-1][j+1]) g[i][j]=1;
        else if (g[i+1][j-1]) g[i][j]=2;
        else if (g[i-1][j+1]) g[i][j]=3;
        else g[i][j]=4;
    }
    else if (g[i+1][j-1]&&g[i-1][j+1]){
        if (g[i-1][j-1]) g[i][j]=5;
        else if (g[i+1][j+1]) g[i][j]=6;
        else g[i][j]=7;
    }
}

void make_graph(){//建图,将不可行格子涂黑
     int i,j,k,tmpx1,tmpx2,tmpy1,tmpy2;
     memset(g,0,sizeof(g));
     for(i=1;i<=n;i++){
        tmpx1=bsch1(bu[i][1].x+1,sx,1,tx);tmpx2=bsch1(bu[i][3].x-1,sx,1,tx);
        tmpy1=bsch1(bu[i][1].y+1,sy,1,ty);tmpy2=bsch1(bu[i][3].y-1,sy,1,ty);
        
        for(j=tmpx1;j<=tmpx2;j++)
          for(k=tmpy1;k<=tmpy2;k++)
             g[j][k]=1;
     }
     
     for(i=2;i<tx;i++)
        for(j=2;j<ty;j++)//if (i%3==0||j%3==0)
           if (!g[i][j]) check(i,j);
     stx=bsch1(stx*3,sx,1,tx);sty=bsch1(sty*3,sy,1,ty);
     edx=bsch1(edx*3,sx,1,tx);edy=bsch1(edy*3,sy,1,ty);
}



int spfa(){
    int i,j,k,ux,uy,ud,vx,vy,vd,dir;
    memset(dis,10,sizeof(dis));//距离初始化为一个很大的数
    memset(inq,0,sizeof(inq));
    queue<int> qx,qy,qd;
    for(j=0;j<4;j++){dis[stx][sty][j]=0;qx.push(stx);qy.push(sty);qd.push(j);inq[stx][sty][j]=1;}
    while(!qx.empty()){
        ux=qx.front();qx.pop();uy=qy.front();qy.pop();ud=qd.front();qd.pop();
        inq[ux][uy][ud]=0;
        for(dir=0;dir<4;dir++)if (check2(g[ux][uy],ud,dir)){
           vx=ux+dx[dir];vy=uy+dy[dir];vd=dir;
           if (vx>=1&&vx<=tx&&vy>=1&&vy<=ty&&check3(g[vx][vy],vd)&&dis[vx][vy][vd]>dis[ux][uy][ud]+(ud==vd?0:1)){
                 dis[vx][vy][vd]=dis[ux][uy][ud]+(ud==vd?0:1);
                 if (!inq[vx][vy][vd]){
                    inq[vx][vy][vd]=1;
                    qx.push(vx);qy.push(vy);qd.push(vd);
                 }
           }
        }
    }
    int ans=INF;
    for(j=0;j<4;j++){
       if (ans>dis[edx][edy][j]) ans=dis[edx][edy][j];
    }
    return ans;
}
    
void add(int a,int b,int c,int d){//将每个坐标自身,+1,-1都加入进行离散
     sx[++tx]=a;sx[++tx]=a-1;sx[++tx]=a+1;
     sx[++tx]=c;sx[++tx]=c-1;sx[++tx]=c+1;
     sy[++ty]=b;sy[++ty]=b-1;sy[++ty]=b+1;
     sy[++ty]=d;sy[++ty]=d-1;sy[++ty]=d+1;
}

inline bool cmp1(int x,int y){return x<y;}
inline bool cmp2(int x,int y){return x<y;}


int main(){
    //freopen("Cin.txt","r",stdin);
    while(1){
        scanf("%d%d%d%d",&stx,&sty,&edx,&edy);
        if (!stx&&!sty&&!edx&&!edy) break;
        scanf("%d",&n); 
        tx=ty=0;
        for(i=1;i<=n;i++){
           scanf("%d%d%d%d",&a,&b,&c,&d);
           a=a*3;b=b*3;c=c*3;d=d*3;
           bu[i][1].init(min(a,c),min(b,d));
           bu[i][3].init(max(a,c),max(b,d));
           bu[i][2].init(bu[i][3].x,bu[i][1].y);
           bu[i][4].init(bu[i][1].x,bu[i][3].y);
           add(a,b,c,d);
        }
        add(-INF*3,-INF*3,INF*3,INF*3);//加入一个无穷大的边界进行离散
        add(stx*3,sty*3,edx*3,edy*3);//加入起始点和终点的坐标
        sort(sx+1,sx+tx+1,cmp1);sort(sy+1,sy+ty+1,cmp2);
        ttx=1;tty=1;
        for(i=2;i<=tx;i++){if (sx[i]!=sx[i-1]) sx[++ttx]=sx[i];}
        for(i=2;i<=ty;i++){if (sy[i]!=sy[i-1]) sy[++tty]=sy[i];}
        tx=ttx;ty=tty;
        
        make_graph();
        
        ans=spfa();
        
        if (ans>10000000) ans=-1;//我不会告诉你忘记输出-1和不会做是一样的结果的
        printf("%d\n",ans);
    }
    return 0;
}
        




________________________________________________________________________________________________________________

现场赛被血虐。。太弱了。


这题明显是要离散化建图,再用spfa求最短路。

但是有几个纠结的地方:1.点与矩形的边x或y坐标相同。对于这点,我的做法是将坐标乘以3。其实乘以2也是可以的。每次加入一个坐标,将该坐标×3,将坐标×3+1,坐标×3,坐标×3-1都加入进行离散。

2.怎样表示矩形。我一开始很愚蠢地要将矩形表示为四条边,每次移动需要判断是否存在边的阻隔。后来在队友的提醒下,我的做法是将矩形覆盖区域涂黑(标记为1),这样就只需判断该点可达与否了。每次将矩形涂黑时,要将矩形左边界+1,右边界-1,上下界也同样。这样矩形的边界就可以走了。但是这又会出现另一种情况,就是有两个相邻的矩形时,它们的边界是不能走的。。。好吧,那么我们就可以这样判断一个点:如果它的左边和右边都是黑的,那么它也是黑的,(上下,左上右下,左下右上同理)。标黑完毕后,就可以进行简单的最短路处理了。

3.还有一点,如果答案为0,也就是没转过向,那么还要判断离散前起点终点坐标是否相同,如果不同,是要转一次的。如果答案不为0,就肯定不需再多转。自己可以画图看看。



希望下次不要再是Bronze了,加油啊~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define NN 400
#define INF 100000000


int stx,sty,edx,edy;
int n,tx,ty,sx[NN],sy[NN],a,b,c,d,ttx,tty,i,ans,flag;
int dis[NN][NN][5],inq[NN][NN][5],g[NN][NN];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};

struct point {
    int x,y;
    void init(int _x,int _y){x=_x;y=_y;};
}bu[NN][10];
  

int bsch1(int val,int v[],int l,int r){//二分寻找离散后的位置,其实暴力也可以吧
    int mid;
    while(l<=r){
       mid=(l+r)>>1;
       if (v[mid]==val) return mid;
       if (v[mid]<val) l=mid+1;
       else r=mid-1;
    }
}

int bsch2(int val,int v[],int l,int r){//这个是找点用的
     int mid,ans=r;
     while(l<=r){
        mid=(l+r)>>1;
        if (v[mid]==val) return mid;
        if (v[mid]>val) {if (ans>mid) ans=mid;r=mid-1;}
        else l=mid+1;
     }
     return ans;
}

inline void check(int i,int j){ //检查格子是否可走
     if (g[i-1][j]&&g[i+1][j]) g[i][j]=1;
     if (g[i][j-1]&&g[i][j+1]) g[i][j]=1;
     if (g[i-1][j-1]&&g[i+1][j+1]||g[i+1][j-1]&&g[i-1][j+1]) g[i][j]=1;
}

void make_graph(){//建图,将不可行格子涂黑
     int i,j,k,tmpx1,tmpx2,tmpy1,tmpy2;
     memset(g,0,sizeof(g));
     for(i=1;i<=n;i++){
        tmpx1=bsch1(bu[i][1].x+1,sx,1,tx);tmpx2=bsch1(bu[i][3].x-1,sx,1,tx);
        tmpy1=bsch1(bu[i][1].y+1,sy,1,ty);tmpy2=bsch1(bu[i][3].y-1,sy,1,ty);
        
        for(j=tmpx1;j<=tmpx2;j++)
          for(k=tmpy1;k<=tmpy2;k++)
             g[j][k]=1;
     }
     
     for(i=2;i<tx;i++)
        for(j=2;j<ty;j++)
           if (!g[i][j]) check(i,j);
     
     /*for(i=1;i<=tx;i++){
        for(j=1;j<=ty;j++){
          printf("%d",g[i][j]);
        }
        printf("\n");
     }*/
           
     stx=bsch2(stx*3,sx,1,tx);sty=bsch2(sty*3,sy,1,ty);
     edx=bsch2(edx*3,sx,1,tx);edy=bsch2(edy*3,sy,1,ty);
     
}

int spfa(){
    int i,j,k,ux,uy,ud,vx,vy,vd,dir;
    memset(dis,10,sizeof(dis));
    memset(inq,0,sizeof(inq));
    queue<int> qx,qy,qd;
    for(j=0;j<4;j++){dis[stx][sty][j]=0;qx.push(stx);qy.push(sty);qd.push(j);inq[stx][sty][j]=1;}
    while(!qx.empty()){
        ux=qx.front();qx.pop();uy=qy.front();qy.pop();ud=qd.front();qd.pop();
        inq[ux][uy][ud]=0;
        for(dir=0;dir<4;dir++){
           vx=ux+dx[dir];vy=uy+dy[dir];vd=dir;
           if (vx>=1&&vx<=tx&&vy>=1&&vy<=ty&&g[vx][vy]==0&&dis[vx][vy][vd]>dis[ux][uy][ud]+(ud==vd?0:1)){
                 dis[vx][vy][vd]=dis[ux][uy][ud]+(ud==vd?0:1);
                 if (!inq[vx][vy][vd]){
                    inq[vx][vy][vd]=1;
                    qx.push(vx);qy.push(vy);qd.push(vd);
                 }
           }
        }
    }
    int ans=INF;
    for(j=0;j<4;j++){
       if (ans>dis[edx][edy][j]) ans=dis[edx][edy][j];
    }
    return ans;
}
    
     
        

void add(int a,int b,int c,int d){//将每个坐标自身,+1,-1都加入进行离散
     sx[++tx]=a;sx[++tx]=a-1;sx[++tx]=a+1;
     sx[++tx]=c;sx[++tx]=c-1;sx[++tx]=c+1;
     sy[++ty]=b;sy[++ty]=b-1;sy[++ty]=b+1;
     sy[++ty]=d;sy[++ty]=d-1;sy[++ty]=d+1;
}

inline bool cmp1(int x,int y){return x<y;}
inline bool cmp2(int x,int y){return x<y;}


int main(){
    //freopen("Cin.txt","r",stdin);
    while(1){
        scanf("%d%d%d%d",&stx,&sty,&edx,&edy);
        if (!stx&&!sty&&!edx&&!edy) break;
        if (stx==edx||sty==edy) flag=1; //标记,如果答案为0,flag==0,那是要再多转一次向的
        else flag=0;
        scanf("%d",&n); 
        tx=ty=0;
        for(i=1;i<=n;i++){
           scanf("%d%d%d%d",&a,&b,&c,&d);
           a=a*3;b=b*3;c=c*3;d=d*3;
           
           bu[i][1].init(min(a,c),min(b,d));
           bu[i][3].init(max(a,c),max(b,d));
           bu[i][2].init(bu[i][3].x,bu[i][1].y);
           bu[i][4].init(bu[i][1].x,bu[i][3].y);
           
           add(a,b,c,d);
           
        }
        add(-INF*3,-INF*3,INF*3,INF*3);//加入一个无穷大的边界进行离散
        sort(sx+1,sx+tx+1,cmp1);sort(sy+1,sy+ty+1,cmp2);
        ttx=1;tty=1;
        for(i=2;i<=tx;i++){if (sx[i]!=sx[i-1]) sx[++ttx]=sx[i];}
        for(i=2;i<=ty;i++){if (sy[i]!=sy[i-1]) sy[++tty]=sy[i];}
        tx=ttx;ty=tty;
        
        make_graph();
        
        ans=spfa();
        
        if (ans==0){
            if (flag==1) ans=0;
            else ans=1;
        }
        if (ans>10000000) ans=-1;//我不会告诉你忘记输出-1和不会做是一样的结果的
        printf("%d\n",ans);
    }
    return 0;
}
        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值