【test】2015.7.28搜索解题报告(二)

Problem  Mud

 

FJ每天6点都准时离开家找BESSIE取奶,但是在前一晚上有一场大雨,田地都充满了泥潭,FJ(0,0)开始, BESSIE(X,Y) (-500 <= X <= 500; -500 <= Y <= 500).他可以看见所有N(1 <= N

<= 10,000)个泥潭位于点(ai,bi) (-500 <= A_i<= 500; -500 <= B_i <= 500),每个泥潭只出现在他所在的点.

FJ可以上下左右四个方向移动,但不想弄脏他的新鞋,请找一条路到BESSIE位置,且不经过泥潭的最短路径. 注意: 坐标全部按平面坐标系来定.

 

 

输入: 第一行: BESSIE位置 X,Y 和 泥潭个数N

      以下 2N+1 行 泥潭位置 A_i  ,  B_I

 

 

输出:  FJ至少走多少步才到达BESSIE.

 

SAMPLE INPUT (file mud.in):

 

1 2 7

0 2

-1 3

3 1

1 1

4 2

-1 1

2 2

 

OUTPUT FORMAT:

 

11

 

 

样例说明:

 

 

INPUT DETAILS:

 

Bessie is at (1, 2). Farmer John sees 7 mud puddles, located at (0,

2); (-1, 3); (3, 1); (1, 1); (4, 2); (-1, 1) and (2, 2). Pictorially:

 

   4 . . . . . . . .

   3 . M . . . . . .

Y  2 . . M B M . M .

   1 . M . M . M . .

   0 . . * . . . . .

  -1 . . . . . . . .

    -2-1 0 1 2 3 4 5

           X

 

OUTPUT FORMAT:

 

* Line 1: The minimum distance that Farmer John has to travel to reach

        Bessie without stepping in mud.

 

SAMPLE OUTPUT (file mud.out):

 

11

 

OUTPUT DETAILS:

 

The best path for Farmer John is (0, 0); (-1, 0); (-2, 0); (-2, 1);

(-2, 2); (-2, 3); (-2, 4); (-1, 4); (0, 4); (0, 3); (1, 3); and (1,

2), finally reaching Bessie.

 

   4 ******* . . . .

   3 * M . * . . . .

Y  2 * . M B M . M .

   1 * M . M . M . .

   0 ***** . . . . .

  -1 . . . . . . . .

    -2-1 0 1 2 3 4 5

 

           X

 

 

【题目分析】

(后面这一大堆是什么鬼!)这道题经过分析就知道了,很普通的一道宽搜题,给出起点终点以及障碍物位置,找最短路线,很经典嘛!只不过数据方面出现了负数。当然这很容易处理,只需要每个数输进来时都加501就行(对于这道题)。

不过我很奇怪如果走不到怎么办……于是我就弄了一个NO WAY……

 

【例程】

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

 

int n,s,m,o,p;

bool num[1005][1005];

int  a[5]={1,0,-1,0},b[5]={0,1,0,-1};

int xx=0,yy=0,ll=0,ans=0,ge=0;

 

struct lj

{

      int x,y,l;

};

lj d[1000001];

 

int main()

{

       freopen("mud.in","r",stdin);

       freopen("mud.out","w",stdout);

      

       cin>>n>>m>>s;

       n+=502;m+=502;

    memset(num,true,sizeof(num));

    for(int i=0;i<s;++i)

    {

          cin>>o>>p;

          num[o+502][p+502]=false;

       }

      

       int H=0,T=0;

       d[0].x=502; 

       d[0].y=502;

       d[0].l=0;

 

    while(H<=T)

    {

              xx=d[H].x;

        yy=d[H].y; 

              ll=d[H].l; 

          if(xx==n&&yy==m)      

        {

             cout<<d[H].l<<endl;

             return 0;

        }

 

        for(int i=0;i<4;++i) 

        {

             if(num[xx+a[i]][yy+b[i]])

            {

                ++T; 

                d[T].x=xx+a[i];d[T].y=yy+b[i];

                d[T].l=ll+1;

                num[d[T].x][d[T].y]=false;

            }

        }

        ++H; 

      }

      cout<<"NO WAY"<<endl;

      return 0;

}

 



 

小明的游戏

提交文件:game.pas/game.cpp

输入文件:game.in

输出文件:game.out

题目描述:

小明最近喜欢玩一个游戏。给定一个n * m的棋盘,上面有两种格子#和@。游戏的规则很简单:给定一个起始位置和一个目标位置,小明每一步能向上,下,左,右四个方向移动一格。如果移动到同一类型的格子,则费用是0,否则费用是1。请编程计算从起始位置移动到目标位置的最小花费。

输入格式:

    输入文件有多组数据。

    输入第一行包含两个整数n,m,分别表示棋盘的行数和列数。

    输入接下来的n行,每一行有m个格子(使用#或者@表示)。

    输入接下来一行有四个整数x1, y1, x2, y2,分别为起始位置和目标位置。

当输入nm均为0时,表示输入结束。

输出格式:

    对于每组数据,输出从起始位置到目标位置的最小花费。每一组数据独占一行。

    输入样例:

输出样例:

2 2

@#
#@

0 0 1 1

2 2

@@

@#

0 1 1 0

0 0

2

0

 

数据规模:

    对于20%的数据满足:1 < = n, m <= 10

    对于40%的数据满足:1 < = n, m <= 300

    对于100%的数据满足:1 < = n, m <= 500

 

 

【题目分析】

这道题看起来是一道很简单的搜索,但实际上我们看数据,用深度搜索显然会爆,但是用宽度搜索呢,又好像不太合适。所以就要采用一种特殊的宽搜。

下面讲两种方法。

第一种:迭代法

普通宽搜都是走了以后要标记已用,但是鉴于此题的特殊性,走了以后并不能标记已用,而是要记录下它的最小花费,然后向四周看,如果走到另一个点的最小花费小于那个点的原先花费,那么就改变其花费,并把这个点加进队列,因为可能这个点的花费小了以后,周围的点花费也会变小。这样一直下去,直到每个点的花费都是最小,程序就结束了。

第二种:双队列

这种方法有些类似于之前学的并查集,就是把相连的一样符号都先查找一次,再查找其周围一圈的不同符号……以此类推,第n次时找到了目标位置,答案就是n

这种方法的实现前提是用双队列,(o)而双队列也有两种方法实现,一是开两个数组,把相同的存到数组一,不同的存到数组二,搜完后把数组二复制到数组一里。

而第二种则是只用一个数组,其中宽搜里的Head指针先放在中间,找到相同的Head就减一,否则尾加一,这样就可以省去开一个数组。

 

【例程1,迭代】

#include<iostream>

#include<cstring>

#include<cstdio>

using namespace std;

 

int n,m,x1,x2,y1,y2;

char ch[502][502];

int  a[5]={-1,0,1,0},b[5]={0,1,0,-1};

int xx,yy,mm,ll;

int jl;

int money[502][502];

bool bo[502][502];

 

struct T

{

       int x,y;

};

T d[500*500*500];

 

int main()

{

       freopen("game.in","r",stdin);

       freopen("game.out","w",stdout);

      

       while(true)

       {

              scanf("%d%d",&n,&m);

              if(n==0&&m==0)

                     return 0;

              memset(ch,'.',sizeof(ch));

              memset(money,0,sizeof(money));

              memset(bo,false,sizeof(bo));

             

              for(int i=1;i<=n;++i)

              for(int j=1;j<=m;++j)

              {

                     cin>>ch[i][j];

                     bo[i][j]=true;

              }

              scanf("%d%d%d%d",&x1,&y1,&x2,&y2);

              x1++;y1++;x2++;y2++;

             

              int H=0,T=0;

              d[0].x=x1; 

              d[0].y=y1;

              bo[x1][y1]=false;

 

            while(H<=T)

            {

                   int ans;

                     xx=d[H].x;

               yy=d[H].y; 

              

 

                     for(int i=0;i<4;++i) 

                    {

                           int nx=xx+a[i],ny=yy+b[i];

                           ans=money[xx][yy];

                if(ch[xx][yy]!=ch[nx][ny])

                           ans++;

                                       

                            if(money[nx][ny]>ans)

                    {

                           money[nx][ny]=ans;

                           ++T; 

                           d[T].x=nx;d[T].y=ny;

                           continue;

                    }  

                              

                            if(bo[nx][ny])

                    {

                           ++T; 

                           d[T].x=nx;d[T].y=ny;       

                                   bo[nx][ny]=false;

                                   money[nx][ny]=ans;

                                   continue;

                    }  

                 }

             ++H; 

        }

              cout<<money[x2][y2]<<endl;;

       }

}



【例程2,双数组】

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

 

int n,m,x1,x2,y1,y2;

int  a[]={-1,0,1,0},

     b[]={0,1,0,-1};

char ch[502][502];

 

int xx,yy;

int ans;

int H,T,H2=0;

bool bo[502][502],tui;

 

struct TT

{

       int x,y;

};

TT d[2500000],d2[2500000];

 

void _set()

{

       for(int i=0;i<H2;++i)

              d[i]=d2[i];           

}

 

int main()

{

       freopen("game.in","r",stdin);

       freopen("game.out","w",stdout);

      

       while(true)

       {

             

              scanf("%d%d",&n,&m);

              if(n==0&&m==0)

                     return 0;

              memset(ch,'.',sizeof(ch));

              memset(bo,false,sizeof(bo));

             

              for(int i=1;i<=n;++i)

                for(int j=1;j<=m;++j)

                {

                     cin>>ch[i][j];

                     bo[i][j]=true;

                }

              scanf("%d%d%d%d",&x1,&y1,&x2,&y2);

              x1++;y1++;

              x2++;y2++;

             

              ans=-1;

              H=0;

              d[H].x=x1; 

              d[H].y=y1;  

      

              bo[x1][y1]=false;

              tui=true;

             

        H2=1;

       

              while(tui)

              {

                     H=0;

                     T=H2-1;

                     H2=0;

                     ++ans;

 

 

                     while(H<=T)

                     {

                            xx=d[H].x;

                      yy=d[H].y;

                      if(xx==x2 && yy==y2)

                      {

                             cout<<ans<<endl;

                             tui=false;

                                   break;

                      }

                     

                      for(int i=0;i<4;++i) 

                           {    

                                  int nx=xx+a[i],ny=yy+b[i];

                                  if(!bo[nx][ny])

                                          continue;

                                 

                       if(ch[xx][yy]!=ch[nx][ny])

                                   {

                                          d2[H2].x=nx;d2[H2].y=ny; ++H2;       

                                   }

                                   else  

                           {

                                  ++T; 

                                  d[T].x=nx;d[T].y=ny;

                                          bo[nx][ny]=false;            

                    }  

                        }

                    ++H;

                     }

                     _set();

             

              }

       }   

}



 

【例程3,单数组】

#include<iostream>

#include<cstring>

#include<cstdio>

using namespace std;

int x1,x2,y1,y2;

int px[4]={-1,0,1,0},py[4]={0,1,0,-1};

struct Tgame

{

       int x;

       int y;

       int l;

};

Tgame que[1000000];

char ch[501][501];

bool pd[501][501];

int main()

{

    freopen("game_pro.in","r",stdin);

    freopen("game_pro.out","w",stdout);

       int n,m;

       while(cin>>n>>m)

       {

              if(n==0&&m==0) break;

             

              memset(que,0,sizeof(que));

              memset(pd,false,sizeof(pd));

             

              for(int i=0;i<n;i++)

              for(int j=0;j<m;j++)

              {

                     cin>>ch[i][j];

              }

             

              cin>>x1>>y1>>x2>>y2;

             

              int head=500000;

              int tail=500000;

              que[head].x=x1;

              que[head].y=y1;

              que[head].l=0;

              pd[x1][y1]=true;

             

              while(head<=tail)

              {

                     if(que[head].x==x2 && que[head].y==y2)

                     {

                            cout<<que[head].l<<endl;

                            break;

                     }

                    

                     int xx=que[head].x;

                     int yy=que[head].y;

                     int len=que[head].l;

                     head++;

                    

                     for(int i=0;i<4;i++)

                     {

                            int nx=xx+px[i];

                            int ny=yy+py[i];

                            if(nx>=0 && nx<n && ny>=0 && nx<m && !pd[nx][ny])

                            {

                                   if(ch[nx][ny]==ch[xx][yy])

                                   {

                                          head--;

                                          pd[nx][ny]=true;

                                          que[head].x=nx;

                                          que[head].y=ny;

                                          que[head].l=len;

                                   }

                                   else

                                   {

                                          tail++;

                                          pd[nx][ny]=true;

                                          que[tail].x=nx;

                                          que[tail].y=ny;

                                          que[tail].l=len+1;

                                   }

                            }

                     }

              }

       }

}



好了,这次测试的报告就写这么多。搜索还是一个比较难的课题,所有还是要多加练习啊!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值