zoukankan      html  css  js  c++  java
  • 8.1搜索专练DFS和BFS

    这是第一次全部做出来的依次练习了,有一些都是做过两遍了的,但是还是错了几回,更多时候我还是应该多注意下细节,就好像章爷笑我 的一样,像什么vis[]标记没清0,什么格式错误,还有什么题目没看清,还是的注意一下了。

    地址: 8.1搜索练习

    Problem A POJ 2488

    A Knight's Journey

    题目大意就是说帮你给你个P*Q的棋盘,让马一次全部走完,每个点只能走一次,而且要按照字典序输出(这句话最坑!!!)。

    这道题做过了两三次了,却老是被那句“字典序输出”给坑死。第一次看到这道题的时候,看到他说的字典序还以为是要让起点最小(虽然现在明白任何一个点作为起点都是可以到达终点的,只要里面有一条路可以遍历完),然后高高兴兴的枚举了起点,心想好简单叽里呱啦就敲完了,测试样例!过了!提交!WA了!然后就回头看代码,检查实在是无力了,在网上一搜,发现别人只用0,0,做起点就过了,马上改了提交!!!还是WA!!心力憔悴的我无力了,有重新找别人的代码,看到别人代码原来还有一小段注释

    int dir[8][2]={-2,-1,-2,1,-1,-2,-1,2,1,-2,1,2,2,-1,2,1};  /*注意此处的数组数据, 为了保证每次的探索都是 符合字典序的*/

    然后才慢慢明白什么叫字典序输出,其实就是要让每一步走的位置要是在能够遍历每个点的前提下,尽量让字典序小。大家可以慢慢体会下。

    贴代码:180 KB     16 ms

     1 #include <stdio.h>
     2 #include <string.h>
     3 int vis[30][30];
     4 
     5 const int d[8][2] = {{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};
     6 int m,n,num,ans[900],IsFind;
     7 
     8 
     9 void dfs(int x,int y)
    10 {
    11     if(x<0 || x>=m || y<0 || y>=n || vis[x][y] || IsFind) return ;
    12     vis[x][y] = 1;
    13     ans[num++] = x*n+y;
    14     if(num == m*n){IsFind = 1; return;}
    15     for(int i=0;i<8 && !IsFind;i++)
    16     {
    17         dfs(x+d[i][0], y+d[i][1]);
    18     }
    19     if(!IsFind)
    20     {
    21         num--;
    22         vis[x][y]=0;
    23     }
    24 }
    25 
    26 int main()
    27 {
    28     int Case,T=0;
    29     while(~scanf("%d", &Case))while(Case--)
    30     {
    31         memset(vis,0,sizeof(vis));
    32         scanf("%d%d", &n, &m);
    33         IsFind = 0;
    34         num=0;
    35         dfs(0,0);
    36         printf("Scenario #%d:
    ", ++T);
    37         if(!IsFind)printf("impossible");
    38         else for(int i=0;i<num;i++)
    39         {
    40             printf("%c%d", ans[i]/n+'A', ans[i]%n+1);
    41         }
    42         printf("
    
    ");
    43         if(!Case)T=0;
    44     }
    45     return 0;
    46 }
    View Code

    Problem B Avoid The Lakes

    Avoid The Lakes

    简单的DFS求最大相连块  392 KB  16 ms

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <queue>
     4 #define MAX(a,b) ((a) > (b) ? (a) : (b))
     5 using namespace std;
     6 
     7 const int d[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
     8 int N,M,K;
     9 int Map[105][105],vis[105][105];
    10 
    11 int DFS(int x,int y)
    12 {
    13     if(x<0 || x>=N || y<0 || y>=M || vis[x][y] || Map[x][y])return 0;
    14     int area = 1;
    15     vis[x][y] = 1;
    16     for(int i=0;i<4;i++)
    17     {
    18         area += DFS(x+d[i][0], y+d[i][1]);
    19     }
    20     return area;
    21 }
    22 
    23 int main()
    24 {
    25     while(~scanf("%d%d%d",&N,&M,&K))
    26     {
    27         memset(Map,1,sizeof(Map));
    28         memset(vis,0,sizeof(vis));
    29         int a,b;
    30         for(int i=0;i<K;i++)
    31         {
    32             scanf("%d%d", &a,&b);
    33             Map[a-1][b-1] = 0;
    34         }
    35         int ans = 0;
    36         for(int i=0;i<N;i++)
    37         {
    38             for(int j=0;j<M;j++)if(!vis[i][j] && !Map[i][j])
    39             {
    40                 int temp = DFS(i,j);
    41                 ans = MAX(ans, temp);
    42             }
    43         }
    44         printf("%d
    ", ans);
    45     }
    46     return 0;
    47 }
    View Code

    Problem C Dungeon Master

    只是将求最短距离从二维增加到三维而已,数组加一维便可以实现436 KB16 ms

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 using namespace std;
     5 
     6 const int Dir[6][3] = {{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
     7 struct node
     8 {
     9     int x,y,z;
    10     int step;
    11 }Start;
    12 char Map[35][35][35];
    13 int vis[35][35][35];
    14 int L,R,C;
    15 
    16 void readData()
    17 {
    18     memset(vis,0,sizeof(vis));
    19     int IsFind_S=0;
    20     for(int i=0;i<L;i++)
    21     {
    22         for(int j=0;j<R;j++)
    23         {
    24             scanf("%s",Map[i][j]);
    25             for(int k=0;k<C && !IsFind_S;k++) if(Map[i][j][k] == 'S')
    26             {
    27                 Start.x = i;
    28                 Start.y = j;
    29                 Start.z = k;
    30                 vis[i][j][k] = 1;
    31                 Start.step = 0;
    32                 IsFind_S = 1;
    33             }
    34         }
    35     }
    36 }
    37 
    38 int BFS()
    39 {
    40     queue<node>q;
    41     q.push(Start);
    42     while(!q.empty())
    43     {
    44         node u = q.front();
    45         q.pop();
    46         int x = u.x, y = u.y, z = u.z;
    47         if(Map[x][y][z] == 'E')return u.step;
    48         for(int i=0;i<6;i++)
    49         {
    50             int nx = x + Dir[i][0], ny = y + Dir[i][1], nz = z + Dir[i][2];
    51             if(nx>=0 && nx<L && ny>=0 && ny<R && nz>=0 && nz < C && Map[nx][ny][nz]!='#' && !vis[nx][ny][nz])
    52             {
    53                 vis[nx][ny][nz] = 1;
    54                 node v;
    55                 v.x = nx; v.y = ny; v.z = nz; v.step = u.step+1;
    56                 q.push(v);
    57             }
    58         }
    59     }
    60     return 0;
    61 }
    62 
    63 int main()
    64 {
    65     while(scanf("%d%d%d%*c", &L, &R, &C) && (L||R||C))
    66     {
    67         readData();
    68         int ans = BFS();
    69         if(!ans)printf("Trapped!
    ");
    70         else printf("Escaped in %d minute(s).
    ",ans);
    71     }
    72     return 0;
    73 }
    View Code

    Problem D Sum It Up

    题目意思就是说给一个T和N个数,让你求出所有的可以让N个数里面找出一些数使得他们的和为T,求所有情况

    由于题目说了每给一个数,这个数就只能用一次,就是说帮你给20,20,20,那么你可以用1个,2个或者3个20,但是你只用第1个或者只用第2个这两种情况都是一样的。这样的话我们每次储存时候就不要重复的储存每个数,而是另外开一个数组保存每个不一样的数,在开一个数组保存每个数的次数。那么在DFS的时候就按照每个不同的数出现的次数,从max~0一直到他们的和为T,就打印数组

    代码里还有注释:228 KB 0 ms

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <queue>
     4 #define MAX(a,b) ((a) > (b) ? (a) : (b))
     5 using namespace std;
     6 
     7 int ans[15];
     8 int N,T,IsFind;
     9 int use[15],num[15],NumOfUse;//NumOdUse用来统计有多好个不同的数,Use放的是不同的数,num放的是每个不同的数出现的次数
    10 int index,k;//index表示DFS到了use[index],ans总共有k个数
    11 
    12 void DFS(int sum)
    13 {
    14     if(sum > T)return ;//和已经大于目标值,不需要继续搜索下去了
    15     if(sum == T)//找到了就打印出来
    16     {
    17         IsFind = 1;//找到了
    18         for(int i=0;i<k;i++)//打印
    19         {
    20             printf("%d%c", ans[i], (i==k-1)? '
    ' : '+');
    21         }
    22         return ;
    23     }
    24     if(index == NumOfUse)return;//已经找到了最后一个,任然不满足,返回
    25     for(int i=num[index];i>=0;i--)//对于第num[index],枚举他出现的次数
    26     {
    27         for(int j=0;j<i;j++)ans[k+j] = use[index];//向ans里放入i个数
    28         index+=1;k+=i;
    29         DFS(sum+use[index-1]*i);
    30         index-=1;k-=i;
    31     }
    32 }
    33 
    34 int main()
    35 {
    36     while(~scanf("%d%d", &T,&N) && N)
    37     {
    38         memset(num,0,sizeof(num));
    39         memset(ans,0,sizeof(ans));
    40         memset(use,0,sizeof(use));
    41         scanf("%d", &use[0]);
    42         num[0] = 1;
    43         NumOfUse = 1;
    44         int temp;
    45         for(int i=1;i<N;i++)
    46         {
    47             scanf("%d", &temp);
    48             if(temp == use[NumOfUse-1])num[NumOfUse-1]++;//由于题目保证输入时非升序,所以直接与前一个比较,相同,次数加1
    49             else {use[NumOfUse] = temp; num[NumOfUse]++;NumOfUse ++;}//不同,数的个数加1
    50         }
    51         IsFind = 0;
    52         printf("Sums of %d:
    ",T);
    53         DFS(0);
    54         if(!IsFind)printf("NONE
    ");
    55     }
    56     return 0;
    57 }
    View Code

    Problem E N皇后问题

    第一次,直接用白书的方法,超时

     1 #include <stdio.h>
     2 #include <string.h>
     3 int vis[3][25],ans,n;
     4 
     5 void dfs(int cur)
     6 {
     7     if(cur == n){ans++;return;}
     8     for(int i=0;i<n;i++)
     9     {
    10         if(!vis[0][i] && !vis[1][i+cur] && !vis[2][cur-i+n])
    11         {
    12             vis[0][i] = vis[1][i+cur] = vis[2][cur-i+n] = 1;
    13             dfs(cur+1);
    14             vis[0][i] = vis[1][i+cur] = vis[2][cur-i+n] = 0;
    15         }
    16     }
    17 }
    18 
    19 
    20 int main()
    21 {
    22     while(~scanf("%d", &n) && n)
    23     {
    24         ans = 0;
    25         memset(vis,0,sizeof(vis));
    26         dfs(0);
    27         printf("%d
    ", ans);
    28     }
    29     return 0;
    30 }
    View Code

    第二次,听了章爷的说法,打表,没有写  if(!n)break;WA了

     1 #include <stdio.h>
     2 #include <string.h>
     3 int ans[11] = {0,1,0,0,2,10,4,40,92,352,724};
     4 int main()
     5 {
     6     int n;
     7     while(~scanf("%d", &n))
     8     {
     9         printf("%d
    ",ans[n]);
    10     }
    11     return 0;
    12 }
    View Code

    第三次,终于过了228 KB15 ms

     1 #include <stdio.h>
     2 #include <string.h>
     3 int ans[11] = {0,1,0,0,2,10,4,40,92,352,724};
     4 int main()
     5 {
     6     int n;
     7     while(~scanf("%d", &n) && n)
     8     {
     9         printf("%d
    ",ans[n]);
    10     }
    11     return 0;
    12 }
    View Code

    Problem F Basic

    此题我没有加入太多想法,有思路就敲了,所以写得有些挫,代码效率也不高,基本思路就是枚举每个点是否放上一个棋子,共有2^16种情况,然后就没放上一个就标记之后不能放上的点,找出者2^16中情况中可以放得数目最多的

    其实也可以直接枚举每个点,放或者不放两种情况,搜索下一个点

    代码 172 KB63 ms

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <queue>
     4 #define MAX(a,b) ((a) > (b) ? (a) : (b))
     5 using namespace std;
     6 
     7 int N;
     8 char Map[5][5],vis[5][5];
     9 const int d[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
    10 
    11 int main()
    12 {
    13     while(~scanf("%d", &N) && N)
    14     {
    15         for(int i=0;i<N;i++)
    16         {
    17             scanf("%s", Map[i]);
    18         }
    19         int Max = 0;
    20         for(int state = 1;state < (1<<(N*N));state++)
    21         {
    22             memset(vis,0,sizeof(vis));
    23             int ans = 0;
    24             for(int i=0;i<(N*N);i++)
    25             {
    26                 if(((1<<i) & state)  &&  Map[i/N][i%N]!='X' && !vis[i/N][i%N])
    27                 {
    28                     ans++;
    29                     vis[i/N][i%N] = 1;
    30                     for(int k=0;k<4;k++)
    31                     {
    32                         int x = i/N +d[k][0], y = i%N+d[k][1];
    33                         while(x>=0 && x<N && y>=0 && y<N && Map[x][y]!='X')
    34                         {
    35                             vis[x][y] = 1;
    36                             x+=d[k][0];  y += d[k][1];
    37                         }
    38                     }
    39                 }
    40             }
    41             Max = MAX(Max, ans);
    42         }
    43         printf("%d
    ", Max);
    44     }
    45     return 0;
    46 }
    View Code

    Problem GAsteroids!

     简单的三维BFS问题

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <queue>
     4 #define Is(a,b) (a>=0 && a<b)
     5 #define MAX(a,b) ((a) > (b) ? (a) : (b))
     6 using namespace std;
     7 
     8 const int Dir[6][3] = {{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
     9 int vis[15][15][15],N;
    10 struct node{int x,y,z,step;};
    11 node Start,End;
    12 char Map[15][15][15];
    13 
    14 int ReadData()
    15 {
    16     memset(Map, 0, sizeof(Map));
    17     char str[10]={0};
    18     scanf("%s %d%*c", str, &N);
    19     for(int i=0;i<N;i++)
    20     {
    21         for(int j=0;j<N;j++)
    22         {
    23             scanf("%s", Map[i][j]);
    24         }
    25     }
    26     int x,y,z;
    27     scanf("%d%d%d",&x,&y,&z);
    28     Start.x = z;   Start.y = y;   Start.z = x;
    29     scanf("%d%d%d",&x,&y,&z);
    30     End.x = z;   End.y = y;   End.z = x;
    31     scanf("%s",str);
    32     if(str[0] == 'E')return 1;
    33     return 0;
    34 }
    35 
    36 int BFS()
    37 {
    38     memset(vis, 0, sizeof(vis));
    39     queue<node>q;
    40     Start.step = 0;
    41     q.push(Start);
    42     node u, v;
    43     vis[Start.x][Start.y][Start.z] = 1;
    44     while(!q.empty())
    45     {
    46         u = q.front();
    47         q.pop();
    48         int x = u.x, y = u.y, z = u.z;
    49         if(x == End.x && y == End.y && z == End.z)return u.step;
    50         for(int i=0;i<6;i++)
    51         {
    52             int nx = x+Dir[i][0], ny = y+Dir[i][1], nz = z+Dir[i][2];
    53             if(Is(nx,N) && Is(ny,N) && Is(nz, N) && !vis[nx][ny][nz] && Map[nx][ny][nz]!='X')
    54             {
    55                 vis[nx][ny][nz] = 1;
    56                 v.x = nx;  v.y = ny;  v.z = nz;
    57                 v.step = u.step+1;
    58                 q.push(v);
    59             }
    60         }
    61     }
    62     return -1;
    63 }
    64 
    65 int main()
    66 {
    67     while(ReadData())
    68     {
    69         int ans = BFS();
    70         if(ans == -1)printf("NO ROUTE
    ");
    71         else printf("%d %d
    ",N,ans);
    72     }
    73 }
    View Code
  • 相关阅读:
    软件项目管理实践之日计划
    VB.NET版机房收费系统—数据库设计
    图的邻接矩阵存储结构
    Java多态特性:重载和覆写的比較
    《实体解析与信息质量》
    cocos2d-x lua 中使用protobuf并对http进行处理
    Memcached 笔记与总结(2)编译 php-memcache 扩展
    大数据的时代意义
    大数据的时代意义
    SPSS输出结果统计表与统计图的专业性编辑及三线表定制格式
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/3230158.html
Copyright © 2011-2022 走看看