欣乐

The eagles are coming!

导航

第四章、万能的搜索


第一节、深度优先搜索
p78 输出全排列的 dfs 方法

#include <stdio.h>
int a[10],book[10],n;

void dfs(int step)
{
  int i;
  if(step==n+1)
  {
    for(i=1;i<=n;i++)
      printf("%d",a[i]);
    printf("\n");
    return;
  }
  for(i=1;i<=n;i++)
  {
    if(book[i]==0)
    {
      a[step]=i;
      book[i]=1;
      dfs(step+1);
      book[i]=0;
    }
  }
  return;
}

int main()
{
  scanf("%d",&n);
  dfs(1);
  getchar();
  return 0;
}
View Code


为了深入了解深搜,用两个方法改变程序:
1、

#include <stdio.h>
int a[10],book[10],n;

void dfs(int step)
{
  int i;
  if(step==n+1)
  {
    for(i=1;i<=n;i++)
      printf("%d",a[i]);
    printf("\n");
    return;
  }
  for(i=1;i<=n;i++)
  {
    if(book[i]==0)
    {
      a[step]=i;
      book[i]=1;
      dfs(step+1);
      printf("i is %d\n",i); // 加这句,观察回溯过程
      book[i]=0;
    }
  }
  return;
}

int main()
{
  //scanf("%d",&n);
  n=3;
  dfs(1);
  getchar();
  return 0;
}
View Code


2、

#include <stdio.h>
int a[10],n;

void dfs(int step)
{
  int i;
  if(step==n+1)
  {
    for(i=1;i<=n;i++)
      printf("%d",a[i]);
    printf("\n");
    return;
  }
  for(i=1;i<=n;i++)
  {
    //把标志与回溯都去掉了。这样没有了剪枝,就可以走遍全部节点
    a[step]=i;
    dfs(step+1);
  }
  return;
}

int main()
{
  scanf("%d",&n);
  dfs(1);
  getchar();
  return 0;
}
View Code

 


p80 1~9九个数填空的DFS方法
( 9!=362880 )

#include <stdio.h>
int a[10],book[10],total=0;

void dfs(int step)
{
  int i;
  if(step==10)
  {
    if(a[1]*100+a[2]*10+a[3] + a[4]*100+a[5]*10+a[6] == 
      a[7]*100+a[8]*10+a[9])
    {
      total++;
      printf("%d%d%d+%d%d%d=%d%d%d\n", a[1], a[2], a[3], a[4], 
        a[5], a[6], a[7], a[8], a[9]);
    }
    return;
  }
  for(i=1;i<=9;i++)
  {
    if(book[i]==0)
    {
      a[step]=i;
      book[i]=1;
      dfs(step+1);
      book[i]=0;
    }
  }
  return;
}

int main()
{
  dfs(1);
  printf("total=%d",total/2);
  getchar();
  return 0;
}
View Code
#include <stdio.h>
int a[10],book[10],total=0,sum=0;

void dfs(int step)
{
  int i;
  if(step==10)
  {
    sum++;
    if(a[1]*100+a[2]*10+a[3] + a[4]*100+a[5]*10+a[6] == 
      a[7]*100+a[8]*10+a[9])
    {
      total++;
      printf("%d%d%d+%d%d%d=%d%d%d\n", a[1], a[2], a[3], a[4], 
        a[5], a[6], a[7], a[8], a[9]);
    }
    return;
  }
  for(i=1;i<=9;i++)
  {
    if(book[i]==0)
    {
      a[step]=i;
      book[i]=1;
      dfs(step+1);
      book[i]=0;
    }
  }
  return;
}

int main()
{
  dfs(1);
  printf("total=%d,sum=%d",total/2,sum);
  getchar();
  return 0;
}
View Code


第二节、解救小哈
p85 用DFS来寻找解救小哈的最短路径数

#include <stdio.h>
int n,m,p,q,min=99999999;
int a[51][51],book[51][51];

void dfs(int x,int y,int step)
{
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} };
  int tx,ty,k;
  if(x==p && y==q)
  {
    if(step<min) min=step;
    return;
  }
  
  for(k=0;k<=3;k++)
  {
    tx=x+next[k][0]; //next第一列
    ty=y+next[k][1]; //第二列
    if(tx<1 || tx>n || ty<1 || ty>m) //新坐标越界
      continue;
    if(a[tx][ty]==0 && book[tx][ty]==0) //新坐标未走过,且无路障
    {
      book[tx][ty]=1;
      dfs(tx,ty,step+1);
      book[tx][ty]=0;
    }
  }
  return;
}

int main()
{
  int i,j,startx,starty;
  scanf("%d %d",&n,&m); //行、列
  for(i=1;i<=n;i++)
    for(j=1;j<=m;j++)
      scanf("%d", &a[i][j]);
  scanf("%d %d %d %d",&startx,&starty,&p,&q); //起点与终点坐标

  book[startx][starty]=1;
  dfs(startx,starty,0);
  printf("%d",min);
  getchar();
  return 0;
}

/*

5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3

*/
View Code

 


第三节、广度优先搜索
p92 BFS解救小哈

#include <stdio.h>
struct note
{
  int x;
  int y;
  int f;
  int s;
};

int main()
{
  struct note que[2501];
  int a[51][51]={0},book[51][51]={0};
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} };
  int head, tail;
  int i, j, k, n, m, startx, starty, p, q, tx, ty, flag;
  scanf("%d %d", &n, &m); //行、列
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]);
  scanf("%d %d %d %d", &startx, &starty, &p, &q); //起点与终点坐标
  head = 1;
  tail = 1;
  que[tail].x = startx;
  que[tail].y = starty;
  que[tail].f = 0;
  que[tail].s = 0;
  tail++;
  book[startx][starty] = 1;

  flag = 0;
  while(head < tail)
  {
    for(k = 0; k <= 3; k++)
    {
      tx = que[head].x + next[k][0];
      ty = que[head].y + next[k][1];
      if(tx < 1 || tx > n || ty < 1 || ty > m) //新坐标越界
        continue;
      if(a[tx][ty] == 0 && book[tx][ty] == 0)  //新坐标未走过,且无路障
      {
        book[tx][ty] = 1;
        que[tail].x = tx;
        que[tail].y = ty;
        que[tail].f = head;
        que[tail].s = que[head].s + 1;
        tail++;
      }
      if(tx == p && ty == q)
      {
        flag = 1;
        break;
      }
    }
    if(flag == 1)
      break;
    head++;
  }
  
  printf("%d\n", que[tail - 1].s);
  getchar(); getchar();
  return 0;
}

/*

5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3

*/
View Code

 


第四节、再解炸弹人
p98 广搜解炸弹人

#include <stdio.h>
struct note
{
  int x;
  int y;
};
char a[20][21];

int getnum(int i, int j)
{
  int sum, x, y;
  sum = 0;
  
  //向上统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    x--;
  }
  
  //向下统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    x++;
  }
  
  //向左统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    y--;
  }
  
  //向右统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    y++;
  }
  
  return sum;
}

int main()
{
  struct note que[401];
  int head,tail;
  int book[20][20]={0};
  int i,k,sum,max=0,mx,my,n,m,startx,starty,tx,ty;
  
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} };
                     
  scanf("%d %d %d %d", &n, &m, &startx, &starty); //n行,m列  起始坐标
                     
  for(i = 0; i <= n - 1; i++)
    scanf("%s", a[i]);  

  head=1;
  tail=1;
  que[tail].x=startx;
  que[tail].y=starty;
  tail++;
  book[startx][starty]=1;
  max=getnum(startx,starty);
  mx=startx;
  my=starty;

  while(head<tail)
  {
    for(k = 0; k <= 3; k++)
    {
      tx = que[head].x + next[k][0];
      ty = que[head].y + next[k][1];
      
      if(tx < 0 || tx > n-1 || ty < 0 || ty > m-1) //新坐标越界
        continue;

      if(a[tx][ty] == '.' && book[tx][ty] == 0)  //新坐标未走过,且无路障
      {
        book[tx][ty] = 1;
        que[tail].x = tx;
        que[tail].y = ty;
        tail++;
        sum=getnum(tx,ty);
        
        //printf("haha %d %d %d\n",tx,ty,sum); //可以观察中间输出过程
        
        if(sum>max)
        {
          max=sum;
          mx=tx;
          my=ty;
        }
      }
    }
    head++;
  }
  
  //printf("将炸弹放置在(%d,%d),最多可以消灭%d个敌人\n", mx,my,max);
  printf("bomp here:(%d,%d),most is:%d\n",mx,my,max);
  getchar();
  getchar();
  return 0;
}

/*
p66 (6,11)改为平地

13 13 3 3
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#.......#..G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.#.#
##G...G.....#
#G#.#G###.#G#
#...G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############

*/
View Code


p103 深搜解炸弹人

#include <stdio.h>
char a[20][21];
int book[20][20],max,mx,my,n,m;

int getnum(int i, int j)
{
  int sum, x, y;
  sum = 0;
  
  //向上统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    x--;
  }
  
  //向下统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    x++;
  }
  
  //向左统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    y--;
  }
  
  //向右统计可以消灭的敌人数
  x = i; y = j;
  while(a[x][y] != '#')
  {
    if(a[x][y] == 'G')
      sum++;
    y++;
  }
  
  return sum;
}

void dfs(int x,int y)
{
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} };  
  int k,sum,tx,ty;
  sum=getnum(x,y);
  
  if(sum>max)
  {
    max=sum;
    mx=x;
    my=y;
  }
  
  for(k = 0; k <= 3; k++)
  {
    tx = x + next[k][0];
    ty = y + next[k][1];
    
    if(tx < 0 || tx > n-1 || ty < 0 || ty > m-1) //新坐标越界
      continue;

    if(a[tx][ty] == '.' && book[tx][ty] == 0)  //新坐标未走过,且无路障
    {
        book[tx][ty] = 1;
        dfs(tx,ty);
    }
  } 
  return;
}  

int main()
{
  int i,startx,starty;
  scanf("%d %d %d %d", &n, &m, &startx, &starty); //n行,m列  起始坐标
                     
  for(i = 0; i <= n - 1; i++)
    scanf("%s", a[i]);  

  book[startx][starty]=1;
  max=getnum(startx,starty);
  mx=startx;
  my=starty;
  dfs(startx,starty);

  //printf("将炸弹放置在(%d,%d),最多可以消灭%d个敌人\n", mx,my,max);
  printf("bomp here:(%d,%d),most is:%d\n",mx,my,max);
  getchar();
  getchar();
  return 0;
}

/*
p66 (6,11)改为平地

13 13 3 3
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#.......#..G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.#.#
##G...G.....#
#G#.#G###.#G#
#...G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############

*/
View Code

 


第五节、宝岛探险
p107 广搜计算小岛面积

#include <stdio.h>
struct note
{
  int x;
  int y;
};

int main()
{
  struct note que[2501];
  int head,tail;
  int a[51][51];
  int book[20][20]={0};
  int i,j,k,sum,n,m,startx,starty,tx,ty;
  
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} };
                     
  scanf("%d %d %d %d", &n, &m, &startx, &starty); //n行,m列  起始坐标
                     
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]); 

  head=1;
  tail=1;
  que[tail].x=startx;
  que[tail].y=starty;
  tail++;
  book[startx][starty]=1;
  sum=1;

  while(head<tail)
  {
    for(k = 0; k <= 3; k++)
    {
      tx = que[head].x + next[k][0];
      ty = que[head].y + next[k][1];
      
      if(tx < 1 || tx > n || ty < 1 || ty > m) //新坐标越界
        continue;

      if(a[tx][ty] > 0 && book[tx][ty] == 0)  //是陆地,且新坐标未走过
      {
        sum++;
        book[tx][ty] = 1;
        que[tail].x = tx;
        que[tail].y = ty;
        tail++;
      }
    }
    head++;
  }

  printf("%d\n",sum);
  getchar();
  getchar();
  return 0;
}

/*

10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0

*/
View Code


p110 深搜计算小岛面积

#include <stdio.h>
int a[51][51];
int book[51][51],n,m,sum;

void dfs(int x,int y)
{
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} };  
  int k,tx,ty;
  for(k = 0; k <= 3; k++)
  {
    tx = x + next[k][0];
    ty = y + next[k][1];
    
    if(tx < 1 || tx > n || ty < 1 || ty > m) //新坐标越界
        continue;

    if(a[tx][ty] > 0 && book[tx][ty] == 0)  //是陆地,且新坐标未走过
    {
      sum++;
      book[tx][ty] = 1;
      dfs(tx,ty);
    }
  } 
  return;
}  

int main()
{
  int i,j,startx,starty;
  scanf("%d %d %d %d", &n, &m, &startx, &starty); //n行,m列  起始坐标
                     
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]); 

  book[startx][starty]=1;
  sum=1;
  dfs(startx,starty); //
  printf("%d\n",sum);
  getchar(); getchar();
  return 0;
}

/*

10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0

*/
View Code


p112 小岛区域成-1

#include <stdio.h>
int a[51][51];
int book[51][51],n,m,sum;
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} }; //放在这里可能更清楚

void dfs(int x,int y,int color)
{
  int k,tx,ty;
  a[x][y]=color; //当前点着色。下面是扩展点。。
  for(k = 0; k <= 3; k++)
  {
    tx = x + next[k][0];
    ty = y + next[k][1];
    
    if(tx < 1 || tx > n || ty < 1 || ty > m) //新坐标越界
        continue;

    if(a[tx][ty] > 0 && book[tx][ty] == 0)  //是陆地,且新坐标未走过
    {
      sum++;
      book[tx][ty] = 1;
      dfs(tx,ty,color); //一旦调用dfs,就着色
    }
  } 
  return;
}  

int main()
{
  int i,j,startx,starty;
  scanf("%d %d %d %d", &n, &m, &startx, &starty); //n行,m列  起始坐标
                     
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]); 

  book[startx][starty]=1;
  sum=1;

  dfs(startx,starty,-1); //

  for(i = 1; i <= n; i++)
  {
    for(j = 1; j <= m; j++)
      printf("%3d", a[i][j]); 
    printf("\n");
  }

  printf("%d\n",sum);
  getchar(); getchar();
  return 0;
}

/*

10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0

*/
View Code


p114 计算小岛个数之漫水填充法

#include <stdio.h>
int a[51][51];
int book[51][51],n,m; //sum用不着了
  int next[4][2] = { {0,1},
                     {1,0},
                     {0,-1},
                     {-1,0} }; //放在这里可能更清楚

void dfs(int x,int y,int color)
{
  int k,tx,ty;
  a[x][y]=color; //当前点着色。下面是扩展点。。
  for(k = 0; k <= 3; k++)
  {
    tx = x + next[k][0];
    ty = y + next[k][1];
    
    if(tx < 1 || tx > n || ty < 1 || ty > m) //新坐标越界
        continue;

    if(a[tx][ty] > 0 && book[tx][ty] == 0)  //是陆地,且新坐标未走过
    {
      //sum++;
      book[tx][ty] = 1;
      dfs(tx,ty,color); //一旦调用dfs,就着色
    }
  } 
  return;
}  

int main()
{
  int i,j,num=0;
  scanf("%d %d", &n, &m); //n行,m列  起始坐标不必有了
                     
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]); 

  //枚举着色
  for(i = 1; i <= n; i++)
  {
    for(j = 1; j <= m; j++)
    {
      if(a[i][j]>0)
      {
        num--;
        book[i][j]=1;
        dfs(i,j,num); //
      }
    }
  }

  for(i = 1; i <= n; i++)
  {
    for(j = 1; j <= m; j++)
      printf("%3d", a[i][j]); 
    printf("\n");
  }

  printf("Number is:%d\n",-num); //小岛个数
  getchar(); getchar();
  return 0;
}

/*

10 10
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0

*/
View Code

 


第六节、水管工游戏
p121 DFS解水管工游戏

#include <stdio.h>
int a[51][51];
int book[51][51],n,m,flag=0;

void dfs(int x,int y,int front)
{
  if(x==n && y==m+1) //已经出口
  {
    flag=1;
    return;
  }
  
  if(x < 1 || x > n || y < 1 || y > m) //坐标越界
    return;
  if( book[x][y] == 1)
    return;
  book[x][y]=1;

  if(a[x][y]>=5 && a[x][y]<=6) //直管
  {
    if(front==1) dfs(x,y+1,1);
    if(front==2) dfs(x+1,y,2);      
    if(front==3) dfs(x,y-1,3);
    if(front==4) dfs(x-1,y,4);
  }

  if(a[x][y]>=1 && a[x][y]<=4) //弯管
  {
    if(front==1)
    {
      dfs(x+1,y,2);
      dfs(x-1,y,4);
    }
    if(front==2)
    {
      dfs(x,y+1,1);
      dfs(x,y-1,3);
    }    
    if(front==3)
    {
      dfs(x-1,y,4);
      dfs(x+1,y,2);
    }    
    if(front==4)
    {
      dfs(x,y+1,1);
      dfs(x,y-1,3);
    }    
  }
  
  book[x][y]=0; //取消标记,即回溯
  return;
}


int main()
{
  int i,j;
  scanf("%d %d", &n, &m); //n行,m列
                     
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]); 

  dfs(1,1,1);
  if(flag==0)
    printf("impossible\n");
  else
    printf("possible\n");
  getchar(); getchar();
  return 0;
}

/*

5 4
5 3 5 3
1 5 3 0
2 3 5 1
6 1 1 5
1 5 5 4

*/
View Code


p124 DFS解水管工游戏,输出路径

#include <stdio.h>
int a[51][51];
int book[51][51],n,m,flag=0;
struct note
{
  int x;
  int y;
} s[100];
int top=0;

void dfs(int x,int y,int front)
{
  int i;
  if(x==n && y==m+1) //已经出口
  {
    flag=1;
    for(i=1;i<=top;i++)
      printf("(%d,%d) ",s[i].x,s[i].y);
    return;
  }
  
  if(x < 1 || x > n || y < 1 || y > m) //坐标越界
    return;
  if( book[x][y] == 1)
    return;
  book[x][y]=1;

  //将当前尝试的坐标入栈
  top++;
  s[top].x=x;
  s[top].y=y;

  if(a[x][y]>=5 && a[x][y]<=6) //直管
  {
    if(front==1) dfs(x,y+1,1);
    if(front==2) dfs(x+1,y,2);      
    if(front==3) dfs(x,y-1,3);
    if(front==4) dfs(x-1,y,4);
  }

  if(a[x][y]>=1 && a[x][y]<=4) //弯管
  {
    if(front==1)
    {
      dfs(x+1,y,2);
      dfs(x-1,y,4);
    }
    if(front==2)
    {
      dfs(x,y+1,1);
      dfs(x,y-1,3);
    }    
    if(front==3)
    {
      dfs(x-1,y,4);
      dfs(x+1,y,2);
    }    
    if(front==4)
    {
      dfs(x,y+1,1);
      dfs(x,y-1,3);
    }    
  }
  
  book[x][y]=0; //取消标记,即回溯
  top--; // 将当前尝试的坐标出栈
  return;
}


int main()
{
  int i,j;
  scanf("%d %d", &n, &m); //n行,m列
                     
  for(i = 1; i <= n; i++)
    for(j = 1; j <= m; j++)
      scanf("%d", &a[i][j]); 

  dfs(1,1,1);
  if(flag==0)
    printf("impossible\n");

  getchar(); getchar();
  return 0;


/*

5 4
5 3 5 3
1 5 3 0
2 3 5 1
6 1 1 5
1 5 5 4

*/
}
View Code

 

 

 


 

oj
以后整理。。。

 

 

 

 

 



top


posted on 2014-10-19 21:42  欣乐  阅读(200)  评论(0编辑  收藏  举报