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
#include
#include
#include
#include
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] 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 x10000000) 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
#include
#include
#include
#include
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]>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 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 x10000000) ans=-1;//我不会告诉你忘记输出-1和不会做是一样的结果的
        printf("%d\n",ans);
    }
    return 0;
}
        

你可能感兴趣的:(ACM/ICPC 2012金华regional现场赛C题 hdu4444 离散化、最短路)