我叫张小黑
张小黑的挣扎生活
posts - 66,  comments - 109,  trackbacks - 0
大家有好的代码请发我邮箱:zhangjia888334@sohu.com 
今天就作了广搜三道题,做个小节。
首先要纠正脑子里的一个错误观念,以前的我的广搜模式就是开个队列,走过的点不能走,队列的类型我还必定是用结构体来做
结构体里放个x,y,n,x-->横坐标,y-->纵坐标,n-->步数
再来几个标准的二维数组,map[Maxh][Maxw]-->描述地图,visit[Maxh][Maxw]--〉描述走没走过.
这都是我以前默认的广搜类型,这三道题我感觉每个都有每个得特色,都有各自特殊情况
首先是第一道:
A:Tom and Jerry
这道题就不需要开队列,他每次走都只有一个方向,每次的行走只有一个目标,所以只要有个while(1)的循环
在循环里加上判断可以break的情况
这道题开始我犯了一个错误,我认为他们再次同时到达以前他们同时到达的位置就失败了
但是我没考虑方向,应该是他们同时到达以前他们到达的位置,并且方向还和以前一样,这样才是失败的
但是及便加上这个也是tle
比如争对以下这种数据:(是死都出不来的)
*...*...*C
......*.**
...*...*..
..........
...*......
*.....*...
...*......
..M......*
...*.*....
.*.*......
所以加上了另外一个很恶心的结束条件,以下是我的代码,这道题有个地方的处理不好,内存很大
#include<iostream>
#define MaxN 
10
#define Max 
400000
int map[MaxN][MaxN];//1表示能走,0表示不能走
int hash[Max];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
int time,mx,my,cx,cy;//当前位置
int mdir,cdir;//方向
void solve()
{
    
int k;
    
int tmp_cx,tmp_cy,tmp_mx,tmp_my;
    
while(1){
        
if(mx==cx&&my==cy){
            printf(
"%d\n",time);
            return;
        }
        k
=cy+cx*10+my*100+mx*1000+cdir*10000+mdir*100000;
        
if(time>1000||hash[k]){
            printf(
"-1\n");
            return;
        }
        tmp_cx
=cx+dx[cdir];
        tmp_cy
=cy+dy[cdir];
        tmp_mx
=mx+dx[mdir];
        tmp_my
=my+dy[mdir];
        
if(tmp_cx<0||tmp_cx>=MaxN||tmp_cy<0||tmp_cy>=MaxN)
            cdir
=(cdir+1)%4;
        
else if(map[tmp_cx][tmp_cy]){
            cx
=tmp_cx;
            cy
=tmp_cy;
        }
        
else cdir=(cdir+1)%4;
        
if(tmp_mx<0||tmp_mx>=MaxN||tmp_my<0||tmp_my>=MaxN)
            mdir
=(mdir+1)%4;
        
else if(map[tmp_mx][tmp_my]){
            mx
=tmp_mx;
            my
=tmp_my;
        }
        
else mdir=(mdir+1)%4;
        
time++;
    }
}
int main()
{
    
int T,i,j;
    char c[
20];
    
while(scanf("%d",&T)!=EOF&&T){
        
while(T--){
            cdir
=mdir=time=0;
            memset(map,
0,sizeof(map));
            memset(hash,
0,sizeof(hash));
            
for(i=0;i<MaxN;i++){
                scanf(
"%s",c);
                
for(j=0;j<MaxN;j++){
                    
if(c[j]!='*')map[i][j]=1;
                    if(c[j]=='C'){cx=i;cy=j;}
                    if(c[j]=='M'){mx=i;my=j;}
                }
            }
            solve();
        }
    }
    return 
0;
}

B Escape
这道题我过的还算顺利,这道题是需要开queue的,因为它首先是需要算最少数的题,然后,当我们重新以相同的方向走到以前走过的点时时不需要入队的,所以他的visit是三维的,runtime error了一次,主要是我的queue 开的太小了,我开始只开了Max*Max,但是一个点可能要入队几次,因为有不同的方向,所以只开这么点是不够的,以下是我的代码:
//一碰见能转弯的一定要转
//随便向左向右
//但是不能往后走,或是回转
//到达房间边缘就算是出来了,算最短步数
#include
<iostream>
#define Max 
80
struct node{
    
int x,y,time,dir;
} queue[
100000];
int map[Max][Max];//1表示能走0表示不能
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int visit[Max][Max][4];//x,y,dir
int h,w;
int sx,sy;//起始位置
int head,tail;
void solve()
{
    
int i,hx,hy,ht,hd;
    
int px,py,d;
    
int m,n;
    head
=tail=0;
    
for(i=0;i<4;i++){
        queue[tail].x
=sx;
        queue[tail].y
=sy;
        queue[tail].dir
=i;
        queue[tail
++].time=0;
        visit[sx][sy][i]
=1;
    }
    
while(head<tail){
        m
=n=0;
        hx
=queue[head].x;
        hy
=queue[head].y;
        ht
=queue[head].time;
        hd
=queue[head++].dir;
        
if(hx==0||hx==h-1||hy==0||hy==w-1){//到达房间边界
            printf(
"%d\n",ht);
            return;
        }
        d
=(hd+1)%4;//向右走
        px
=hx+dx[d];py=hy+dy[d];//px,py不会越界,因为hx,hy不在边界上,再走一步也不会越界
        
if(map[px][py]){
            m
=1;
            
if(!visit[px][py][d]){
                queue[tail].x
=px;
                queue[tail].y
=py;
                queue[tail].time
=ht+1;
                queue[tail
++].dir=d;
                visit[px][py][d]
=1;}
        }
        d
=(hd+3)%4;
        px
=hx+dx[d];py=hy+dy[d];//同样不会越界
        
if(map[px][py]){
            n
=1;
            
if(!visit[px][py][d]){
                queue[tail].x
=px;
                queue[tail].y
=py;
                queue[tail].time
=ht+1;
                queue[tail
++].dir=d;
                visit[px][py][d]
=1;}
        }
        px
=hx+dx[hd];py=hy+dy[hd];
        
if(!m&&!n&&map[px][py]&&!visit[px][py][hd]){
            queue[tail].x
=px;
            queue[tail].y
=py;
            queue[tail].time
=ht+1;
            queue[tail
++].dir=hd;
            visit[px][py][hd]
=1;
        }
    }
    printf(
"-1\n");
}
int main()
{
    
int T,i,j;
    char c[
100];
    scanf(
"%d",&T);
    
while(T--){
        memset(map,
0,sizeof(map));
        memset(visit,
0,sizeof(visit));
        memset(queue,
0,sizeof(queue));
        scanf(
"%d%d",&h,&w);
        
for(i=0;i<h;i++){
            scanf(
"%s",c);
            
for(j=0;j<w;j++){
                
if(c[j]!='#')map[i][j]=1;
                if(c[j]=='@'){sx=i;sy=j;}
            }
        }
        solve();
    }
    return 
0;
}


C Push!
这道题我其实做了两层搜索,我代码有点冗长,看别人都很短,不知道他们是怎么实现的
首先解释下我的
int visit[Max][Max][Max][Max];
//cx,cy,mx,my
在每次定位cx,cy(箱子坐标)好时,我们都要设置visit以下,主要是把箱子附近的人可到达位置定为1,这样下次再遍历到就不用加入队列了
这道题我还蛮像写清楚我是怎么想的,但还真有点混乱,尤其是这一段
for(i=0;i<4;i++){
   pcx=hcx+dx[i]; pcy=hcy+dy[i];
   pmx=hcx+dx[(i+2)%4]; pmy=hcy+dy[(i+2)%4];
   if(pmx<0||pmx>=h||pcx<0||pcy>=w)continue;
   if(pcx<0||pcx>=h||pcy<0||pcy>=w)continue;
   if(map[pcx][pcy]==1)continue;
   if(visit[pcx][pcy][hcx][hcy])continue;
   if(!visit[hcx][hcy][pmx][pmy])continue;
   push(hcx,hcy,pcx,pcy,hnum+1);
   set_visit(hcx,hcy,pcx,pcy);
  }
这两个visit[][][]的判断是两层visit的判断,要想清楚
这道题基本上写完后没什么错,都是些什么x写成y,p写成q的错误,这还多亏了pc,我边聊天,边写的
以下是我的代码:
#include<iostream>
#define Max 
7
struct node{
    
int cx,cy,mx,my,num;
}queue[
1000];
int visit[Max][Max][Max][Max];
//cx,cy,mx,my
int map[Max][Max];
//对于人来说边界不能走,不能走,也不能,其余的可以
//对于箱子来说表示不能走边界不能走,其余的都能走
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int man_x,man_y,cargo_x,cargo_y;
int w,h;
int head,tail;
void push(
int x1,int y1,int x2,int y2,int n)
{
    queue[tail].mx
=x1;
    queue[tail].my
=y1;
    queue[tail].cx
=x2;
    queue[tail].cy
=y2;
    queue[tail
++].num=n;
}
void set_visit(
int x1,int y1,int x2,int y2)
{
//men:(x1,y1),cargo:(x2,y2)
    
int qnx[1000]={0},qny[1000]={0};
    
int p,q,px,qy,i;
    
int fis=0,end=0;
    qnx[
end]=x1; qny[end++]=y1;
    visit[x2][y2][x1][y1]
=1;
    
while(fis<end){
        p
=qnx[fis]; q=qny[fis++];
        
for(i=0;i<4;i++){
            px
=p+dx[i]; qy=q+dy[i];
            
if(px<0||px>=h||qy<0||qy>=w)continue;
            
if(map[px][qy]==1)continue;
            
if(px==x2&&qy==y2)continue;//注意
            
if(visit[x2][y2][px][qy])continue;
            qnx[
end]=px; qny[end++]=qy;
            visit[x2][y2][px][qy]
=1;
        }
    }
}
void solve()
{
    
int i;
    
int hmx,hmy,hcx,hcy,hnum;
    
int pcx,pcy,pmx,pmy;
    push(man_x,man_y,cargo_x,cargo_y,
0);
    set_visit(man_x,man_y,cargo_x,cargo_y);
    
while(head<tail){
        hmx
=queue[head].mx;
        hmy
=queue[head].my;
        hcx
=queue[head].cx;
        hcy
=queue[head].cy;
        hnum
=queue[head++].num;
        
if(map[hcx][hcy]==3){
            printf(
"%d\n",hnum);
            return;
        }
        
for(i=0;i<4;i++){
            pcx
=hcx+dx[i]; pcy=hcy+dy[i];
            pmx
=hcx+dx[(i+2)%4]; pmy=hcy+dy[(i+2)%4];
            
if(pmx<0||pmx>=h||pcx<0||pcy>=w)continue;
            
if(pcx<0||pcx>=h||pcy<0||pcy>=w)continue;
            
if(map[pcx][pcy]==1)continue;
            
if(visit[pcx][pcy][hcx][hcy])continue;
            
if(!visit[hcx][hcy][pmx][pmy])continue;
            push(hcx,hcy,pcx,pcy,hnum
+1);
            set_visit(hcx,hcy,pcx,pcy);
        }
    }
    printf(
"-1\n");
}
int main()
{
    
int i,j;
    
while(scanf("%d%d",&w,&h)!=EOF&&w&&h){
        head
=tail=0;
        memset(map,
0,sizeof(map));
        memset(queue,
0,sizeof(queue));
        memset(visit,
0,sizeof(visit));
        
for(i=0;i<h;i++)
            
for(j=0;j<w;j++){
                scanf(
"%d",&map[i][j]);
                
if(map[i][j]==2){cargo_x=i;cargo_y=j;}
                
else if(map[i][j]==4){man_x=i;man_y=j;}
            }
        solve();
    }
    return 
0;
}
ps: 我想到了个push我犯了个错误,就是set_visit的那个搜索,因为这个搜索其实是针对人所能到达位置的搜索
而人有两个地方是到不了的,一个是箱子的地方,一个是障碍物的地方
而箱子这个就要注意了,因为箱子位置是动态的,所以不能通过map[][]是否等于2来判断。
posted on 2008-04-10 00:57 zoyi 阅读(323) 评论(0)  编辑 收藏 引用 所属分类: acm搜索

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


欢迎光临 我的白菜菜园

<2008年4月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

常用链接

留言簿(8)

随笔分类

随笔档案

文章档案

相册

acmer

online judge

队友

技术

朋友

搜索

  •  

最新评论

阅读排行榜

评论排行榜