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
  • 相关阅读:
    poj 1328 Radar Installation (贪心)
    hdu 2037 今年暑假不AC (贪心)
    poj 2965 The Pilots Brothers' refrigerator (dfs)
    poj 1753 Flip Game (dfs)
    hdu 2838 Cow Sorting (树状数组)
    hdu 1058 Humble Numbers (DP)
    hdu 1069 Monkey and Banana (DP)
    hdu 1087 Super Jumping! Jumping! Jumping! (DP)
    必须知道的.NET FrameWork
    使用记事本+CSC编译程序
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/3230158.html
Copyright © 2011-2022 走看看