• 第三次组队赛 (DFS&BFS)


     网站:CSUST 8月1日

    先总结下,不得不说死的很惨,又是第三就不说了,一共7道题,AC了5道,但是有一个组三个人是做的个人赛,有两人AK了.......Orz,然后深搜还是大问题,宽搜倒是不急了。

    而且,其中还有一题是水过去的。唉,不说了,好好看。╮(╯▽╰)╭

    A    骑士历遍问题:给出m,n,指大小为m*n的棋盘,问骑士是否能遍历整个棋盘,要求把路径打出来,(要按字典序)A Knight's Journey   POJ 2488

    网上找到了个很好地代码,解释很清晰:http://www.slyar.com/blog/poj-2488-c.html    (以下解释来自这里)

    Slyar:说一下题目大意。给出一个国际棋盘的大小,判断马能否不重复的走过所有格,并记录下其中按字典序排列的第一种路径。

    "马的遍历"是一道经典回溯题,当然还是DFS...这题有3个要密切注意的地方:

    1、题目要求以"lexicographically"方式输出,也就是字典序...一开始没看懂这个词结果WA了N次...要以字典序输出路径,那么方向数组就要以特殊的顺序排列了...这样只要每次从dfs(1,1)开始搜索,第一个成功遍历的路径一定是以字典序排列...

    2、国际象棋的棋盘,横行为字母,表示横行坐标的是y;纵行为数字,表示纵行的坐标是x...一开始又搞反了...

    代码:16MS

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 using namespace std;
     5 int map[30][30],x[30],y[30];
     6 int d[8][2]={{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},{1, -2}, {1, 2}, {2, -1}, {2, 1}};  //字典序
     7 int m,n,sign,step;
     8 void dfs(int i,int j)
     9 {
    10     int a,b,k;
    11     if(sign)   //以历遍,跳出
    12         return ;
    13     step++;
    14     x[step]=i;   //当前位置
    15     y[step]=j;
    16     if(step==m*n)    //步数=格子数
    17     {
    18         sign=1;
    19         return ;
    20     }
    21     map[i][j]=1;   //标记
    22     for(k=0;k<8;k++)
    23     {
    24         b=j+d[k][0];   //注意
    25         a=i+d[k][1];
    26         if(map[a][b]==0 && a>0 && b>0 && a<=m && b<=n)
    27         {
    28             dfs(a,b);
    29             step--;   //不符合要求是回溯步数
    30 
    31         }
    32     }
    33     map[i][j]=0;   //返回
    34 }
    35 int main()
    36 {
    37     int T,i,t=0;
    38     scanf("%d",&T);
    39     while(T--)
    40     {
    41         scanf("%d%d",&m,&n);
    42         t++;
    43         memset(map,0,sizeof(map));
    44         step=0;
    45         sign=0;
    46         dfs(1,1);
    47         printf("Scenario #%d:
    ", t);
    48         if(sign)
    49             {
    50                 for(i=1;i<=m*n;i++)
    51                    printf("%c%d",y[i]+64,x[i]); //注意这里,先是y,再是x
    52                 printf("
    
    "); //要空一行
    53             }
    54         else printf("impossible
    
    "); //要空一行
    55     }
    56     return 0;
    57 }

    B 大意是:找出最大的湖泊的格子数,只能上下左右,对角不算相连    Avoid The Lakes     POJ 3620

    代码:      16ms  BFS

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<string.h>
     4 using namespace std;
     5 int d[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
     6 int map[105][105];
     7 int m,n;
     8 class A
     9 {
    10 public:
    11     int a;
    12     int b;
    13 };
    14 A q[10025];
    15 void bfs()
    16 {
    17     A r,t;
    18     int i,j,ans,k,maxn=0;
    19     for(j=1;j<=m;j++)    //扫描
    20         for(k=1;k<=n;k++)
    21         {
    22             if(map[j][k]==1)
    23             {
    24                ans=1;
    25                int g=0;
    26                int h=0;
    27                map[j][k]=0;  //标记
    28                q[g].a=j;   //开始的位置
    29                q[g].b=k;
    30                g++;
    31                while(h!=g)
    32                {
    33                   r=q[h++];
    34                   for(i=0;i<4;i++)
    35                   {
    36                      t.a=r.a+d[i][0];
    37                      t.b=r.b+d[i][1];
    38                      if(t.a>0 && t.a<=m && t.b>0 && t.b<=n && map[t.a][t.b]==1) //满足条件
    39                      {
    40                          q[g++]=t;
    41                          map[t.a][t.b]=0;   //标记
    42                          ans++;
    43                      }
    44                   }
    45                }
    46                if(maxn<ans)   //找出最大值
    47                 maxn=ans;
    48             }
    49         }
    50     cout<<maxn<<endl;
    51 }
    52 int main()
    53 {
    54     int i,j,k,x;
    55     memset(map,0,sizeof(map));
    56     while(~scanf("%d%d%d",&m,&n,&x))
    57     {
    58         for(i=0;i<x;i++)
    59         {
    60             scanf("%d%d",&j,&k);
    61             map[j][k]=1;
    62         }
    63         bfs();
    64     }
    65     return 0;
    66 }

    另一种方法:DFS      16MS

     1 #include<iostream>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stdio.h>
     5 using namespace std;
     6 int b[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
     7 int a[105][105];
     8 int n,m,s;
     9 void dfs(int i,int j)
    10 {
    11     int k,x,y;
    12     s++;
    13     a[i][j]=0;  //标记
    14     for(k=0;k<4;k++)
    15     {
    16         x=i+b[k][0];
    17         y=j+b[k][1] ;
    18         if(x>0&&x<=n&&y>0&&y<=m&&a[x][y]==1)  //满足条件
    19             dfs(x,y);
    20     }
    21 }
    22 int main()
    23 {
    24     int t,a1,b1,i,j,MAX;
    25     while(~scanf("%d%d%d",&n,&m,&t))
    26     {
    27         s=0;
    28         memset(a,0,sizeof(a));
    29         for(i=0;i<t;i++)
    30         {
    31             scanf("%d %d",&a1,&b1);
    32             a[a1][b1]=1;
    33         }
    34         MAX=0;
    35         for(i=1;i<=n;i++)
    36             for(j=1;j<=m;j++)   // 遍历能够开始的点
    37             if(a[i][j]==1)
    38             {
    39                 dfs(i,j);
    40                 if(s>MAX)   //找到最大值
    41                     MAX=s;
    42                 s=0;
    43             }
    44         printf("%d
    ",MAX);
    45     }
    46     return 0;
    47 }

    C 大意是:一个Z层x*y的楼房,要从起点到中点,问最少要走多少步?     6个方向    Dungeon Master    POJ 2251

    代码:     0MS

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 int number,Z,X,Y,x1,y1,z1,x2,y2,z2;
     6 const int add[6][3]={{0,1,0},{0,-1,0},{1,0,0},{-1,0,0},{0,0,1},{0,0,-1}};   //上下左右前后6个方向
     7 char a[30][30][30];
     8 class K
     9 {
    10 public:
    11     int x,y,z,step;
    12 }k[1000000];
    13 void bfs(int z,int x,int y)
    14 {
    15     int f=0,r=1,i,hx,hy,hz;
    16     k[0].x=x;   //开始位置
    17     k[0].y=y;
    18     k[0].z=z;
    19     k[0].step=0;
    20     a[z][x][y]='#';   //标记
    21     while(f<r)
    22     {
    23       for(i=0;i<6;i++)
    24         {
    25             hx=k[f].x+add[i][0];
    26             hy=k[f].y+add[i][1];
    27             hz=k[f].z+add[i][2];
    28             if(hx>=0 && hx<X && hy>=0 && hy<Y && hz>=0 && hz<Z && (a[hz][hx][hy]=='.' ||a[hz][hx][hy]=='E') )
    29             {
    30                 if(a[hz][hx][hy]=='E')
    31                     {number=k[f].step+1; return;}
    32                 k[r].x=hx;
    33                 k[r].y=hy;
    34                 k[r].z=hz;
    35                 k[r++].step=k[f].step+1;
    36                  a[hz][hx][hy]='#';
    37             }
    38         }
    39         f++;
    40     }
    41     return;
    42 }
    43 int main()
    44 {
    45     while(scanf("%d%d%d",&Z,&X,&Y)&&Z&&Y&&X)
    46     {
    47         int i,j,k;
    48         memset(a,0,sizeof(a));
    49         for(i=0;i<Z;i++)   //输入地图
    50             for(j=0;j<X;j++)
    51                scanf("%s",a[i][j]);
    52         for(i=0;i<Z;i++)
    53           for(j=0;j<X;j++)
    54             for(k=0;k<Y;k++)
    55               if(a[i][j][k]=='S')   //起点
    56                {
    57                 x1=j;
    58                 y1=k;
    59                 z1=i;
    60                }
    61         number=0;
    62         bfs(z1,x1,y1);
    63         if(number==0)    
    64             printf("Trapped!
    ");
    65         else
    66             printf("Escaped in %d minute(s).
    ",number);
    67     }
    68     return 0;
    69 }

    D  大意是:给出一个数m,要用n个数来凑,这n个数分别是a1,a2,a3a.....an.输出加法式    Sum It Up    HDU 1258

    代码:      15MS

     1 #include<stdio.h>
    2
    int t,n,flag,a[20],b[20];
    3 void dfs(int j,int k,int g)
     4 {
     5     int i;
     6    if(j>t)
     7     return ;
     8    if(j==t)    //凑成了t
     9    {
    10       flag=0;   //至少有一种凑的方法
    11       for(i=0;i<g-1;i++)
    12          printf("%d+",b[i]);
    13       printf("%d
    ",b[g-1]);   //打出等式
    14       return ;
    15    }
    16    int last=-1;
    17    for(i=k;i<n;i++)   //和每个排在自己之后的数加一次
    18    {
    19      if(j+a[i]>t)   //超过就跳过
    20       continue;
    21     if(a[i]!=last)    //不等于最后加的一个数,否则等式一样
    22     {
    23       last=b[g]=a[i];    //更新最后加的数
    24       dfs(j+a[i],i+1,g+1);
    25     }
    26    }
    27 }
    28 int main()
    29 {
    30     int i;
    31    while(~scanf("%d%d",&t,&n)&&n&&t)
    32    {
    33      flag=1;
    34      for(i=0;i<n;i++)
    35           scanf("%d",&a[i]);
    36       printf("Sums of %d:
    ",t);
    37       dfs(0, 0, 0);
    38       if(flag)
    39         printf("NONE
    ");
    40    }
    41 }

     另一份代码:    0ms

     1 #include <stdio.h>
     2 #include<string.h>
     3 const int N=20;
     4 int a[N],n,t,flag;
     5 bool vis[N];
     6 void print()
     7 {
     8     flag=1;
     9     bool bol=0;
    10     int i;
    11     for (i=1;i<=n;i++)
    12         if (vis[i])    //判断要不要加
    13     {
    14         if (bol) printf("+%d",a[i]);
    15         else {bol=1; printf("%d",a[i]);}   //加的第一个数
    16     }
    17     printf("
    ");
    18 }
    19 void dfs(int s,int p)
    20 {
    21     if (s==t) {print(); return;}
    22     int i;
    23     for (i=p+1;i<=n;i++)   //s和最后一个加数之后所有的数加一次
    24     {
    25         vis[i]=1;   //标记,代表加了这个数
    26         if (s+a[i]<=t)
    27             dfs(s+a[i],i);
    28         vis[i]=0;      //不满足则退回到上一步
    29         while (i<=n && a[i]==a[i+1])    //一样的数不用再加,否则会重复
    30             i++;
    31     }
    32 }
    33 int main()
    34 {
    35     int i;
    36     while (scanf("%d%d",&t,&n),n||t)
    37     {
    38         flag=0;
    39         for (i=1;i<=n;i++)
    40             scanf("%d",&a[i]);
    41         printf("Sums of %d:
    ",t);
    42         dfs(0,0);
    43         if (!flag) printf("NONE
    ");
    44     }
    45     return 0;
    46 }

    E大意是:在N*N的棋盘上放N个皇后,每两个皇后不能在同一行,同一列,也不能再同一斜线上(45°斜线),问有多少种方法?

    这一道题我们是水过去的,因为规定了N<=10,所以只有10种情况,一一列举出来。╮(╯▽╰)╭

    以下解释&&代码来自http://blog.sina.com.cn/s/blog_696187fd0100p5ri.html#       (我修改了一些地方)

    方法一:  递归回溯    //会超时......

     1 #include<stdio.h>
     2 #include<math.h>
     3 #define N 15
     4 int n; //皇后个数
     5 int sum = 0; //可行解个数
     6 int x[N]; //皇后放置的列数
     7 int place(int k)
     8 {
     9     int i;
    10     for(i=1;i<k;i++)
    11       if(fabs(k-i)==fabs(x[k]-x[i]) || x[k] == x[i])  //fabs(k-i)==fabs(x[k]-x[i])是在同一斜线上,x[k] == x[i]在同一列
    12         return 0;
    13     return 1;
    14 }
    15 int queen(int t)
    16 {
    17     if(t>n) //当放置的皇后超过n时,可行解个数加1
    18       sum++;
    19     else
    20       for(int i=1;i<=n;i++)
    21       {
    22           x[t] = i; //标明第t个皇后放在第i列
    23           if(place(t)) //如果可以放在某一位置,则继续放下一皇后
    24             queen(t+1);
    25       }
    26     return sum;
    27 }
    28 int main()
    29 {
    30     while(~scanf("%d",&n)&&n)
    31     {
    32         sum=0;
    33         int t = queen(1);
    34         printf("%d
    ",t);
    35     }
    36     return 0;
    37 }

    方法二:迭代回溯      可以理解但是....他是肿么想出来的.....其实和上面那个方法差不多,但是不是用递归实现的

     1 #include<stdio.h>
     2 #include<math.h>
     3 #define N 15
     4 int n;
     5 int sum = 0;
     6 int x[N];
     7 int place(int k)   //判断能不能放这~~~
     8 {
     9     int i;
    10     for(i=1;i<k;i++)
    11       if(fabs(k-i)==fabs(x[k]-x[i]) || x[k] == x[i])   //fabs(k-i)==fabs(x[k]-x[i])是在同一斜线上,x[k] == x[i]是在同一列上
    12         return 0;
    13     return 1;
    14 }
    15 int queen()
    16 {
    17       x[1] = 0;
    18       int t=1;
    19       while(t>0)
    20       {
    21           x[t]+=1;
    22           while(x[t]<=n && !place(t))    //一列列试,不行则放下一列
    23               x[t]++;
    24           if(x[t]<=n )
    25             if(t==n)
    26               sum++;
    27             else
    28               x[++t] = 0;
    29           else
    30             t--;   //满了则退回一步
    31       }
    32       return sum;
    33 }
    34 int main()
    35 {
    36     int t;
    37     while(~scanf("%d",&n),n)
    38     {
    39         sum=0;
    40         t = queen();
    41         printf("%d
    ",t);
    42     }
    43     return 0;
    44 }

    这样用记忆法才不会超时      15MS

     1 #include <stdio.h>
     2 #include <iostream>
     3 #include <math.h>
     4 using namespace std;
     5 int n,x[15],sum,a[15];
     6 int place(int i)
     7 {
     8     for(int j=1;j<i;j++)
     9         if(fabs(i-j)==fabs(x[i]-x[j]) || x[i]==x[j])
    10             return 0;
    11     return 1;
    12 }
    13 int qeen(int i)
    14 {
    15     if(i>n)
    16         sum++;
    17     else
    18         for(int j=1;j<=n;j++)
    19         {
    20             x[i]=j;
    21             if(place(i))
    22                 qeen(i+1);
    23         }
    24     return sum;
    25 }
    26 int main()
    27 {
    28     for(n=1;n<=10;n++)
    29     {
    30         sum=0;
    31        a[n]=qeen(1);
    32     }
    33     while(~scanf("%d",&n)&&n)
    34         printf("%d
    ",a[n]);
    35     return 0;
    36 }

    E 大意是:找出棋盘上最多能放的棋子数,不能同一行同一列(隔开了就可以),允许在同一斜线上。

    如图:

    1:棋盘。2:正确的方法(也是最多的),3正确,4&5错误.

    和N皇后有点像,指不过斜线也可以放,而且有墙,隔开也可以放。

    代码:     来自:http://blog.csdn.net/hcbbt/article/details/9420387       15MS,头文件加上#include<iostream> using namespace std;之后时间为0MS

     1 #include <cstdio>
     2 const int maxn = 5;
     3 char map[maxn][maxn];
     4 int ans, n;
     5 bool isok(int x, int y)
     6 {
     7     for (int i = x + 1; i <= n && map[i][y] != 'X'; i++)   //遇到'X'就不再搜了
     8         if(map[i][y] == '0')
     9             return false;
    10     for (int i = x - 1; i >= 1 && map[i][y] != 'X'; i--)
    11         if(map[i][y] == '0')
    12             return false;
    13     for (int i = y + 1; i <= n && map[x][i] != 'X'; i++)
    14         if (map[x][i] == '0')
    15             return false;
    16     for (int i = y - 1; i >= 1 && map[x][i] != 'X'; i--)
    17         if (map[x][i] == '0')
    18             return false;
    19     return true;
    20 }
    21 void dfs(int x, int y, int p)
    22 {
    23     for (int i = 1; i <= n; i++)
    24         for (int j = 1; j <= n; j++)
    25             if (map[i][j] == '.' && isok(i, j))
    26             {
    27                 map[i][j] = '0';   //代表已经放了一颗棋子
    28                 dfs(i, j, p + 1);
    29                 map[i][j] = '.';
    30             }
    31     if (ans < p)
    32         ans = p;
    33 }
    34 int main()
    35 {
    36     while (scanf("%d", &n) && n)
    37     {
    38         gets(map[0]);   //可改成用scanf("%s",map[i]+1);来输入
    39         for (int i = 1; i <= n; i++)
    40             gets(map[i] + 1);
    41         ans = 0;
    42         dfs(1, 1, 0);
    43         printf("%d
    ", ans);
    44     }
    45     return 0;
    46 }

     G:G和C几乎一模一样,就不解释了:

    代码:         31MS

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 int number,quan,N,x1,y1,z1,x2,y2,z2;
     6 const int add[6][3]={{0,1,0},{0,-1,0},{1,0,0},{-1,0,0},{0,0,1},{0,0,-1}};
     7 char a[30][30][30];
     8 class K
     9 {
    10 public:
    11     int x,y,z,step;
    12 }k[1000000];
    13 void bfs(int z,int x,int y)
    14 {
    15     int f=0,r=1,i,hx,hy,hz;
    16     memset(k,0,sizeof(k));
    17     k[0].x=x;
    18     k[0].y=y;
    19     k[0].z=z;
    20     k[0].step=0;
    21     a[z][x][y]='X';
    22     while(f<r)
    23     {
    24         for(i=0;i<6;i++)
    25         {
    26             hx=k[f].x+add[i][0];
    27             hy=k[f].y+add[i][1];
    28             hz=k[f].z+add[i][2];
    29 
    30             if(hx>=0 && hx<N && hy>=0 && hy<N && hz>=0 && hz<N && a[hz][hx][hy]=='O')
    31             {
    32                 if(hz==z2 && hx==x2 && hy==y2)
    33                     {number=k[f].step+1; return;}
    34                 k[r].x=hx;
    35                 k[r].y=hy;
    36                 k[r].z=hz;
    37                 k[r++].step=k[f].step+1;
    38                 a[hz][hx][hy]='X';
    39             }
    40         }
    41         f++;
    42     }
    43     return;
    44 }
    45 
    46 int main()
    47 {
    48     char w[4],q[10];
    49     while(~scanf("%s",q))
    50     {
    51         scanf("%d",&N);
    52         int i,j,k;
    53         memset(a,0,sizeof(a));
    54         for(i=0;i<N;i++)
    55         {
    56             for(j=0;j<N;j++)
    57             scanf("%s",a[i][j]);
    58         }
    59         scanf("%d%d%d",&z1,&x1,&y1);
    60         scanf("%d%d%d",&z2,&x2,&y2);
    61         scanf("%s",w);
    62         quan=0;
    63         if(a[z2][x2][y2]=='O') quan++;
    64         if(a[z2][x2][y2]=='X') {a[z2][x2][y2]='O';quan--;}
    65         number=0;
    66         if(z1==z2 && x1==x2 && y1==y2) {printf("%d 0
    ",quan);continue;}
    67         bfs(z1,x1,y1);
    68         if(number==0)
    69             printf("NO ROUTE
    ");
    70         else
    71             printf("%d %d
    ",number+quan,number);
    72     }
    73     return 0;
    74 }
  • 相关阅读:
    CentOS7.0下Zabbix3.4至Zabbix4.0的升级步骤(Proxy)
    CentOS6.5下Zabbix3.0升级到4.0
    kubernetes相关概念
    更新OpenSSL
    fish 常用主题推荐
    [转] Adobe acrobat 破解教程
    [转]latex符号
    bank conflct 一句话总结
    Ubuntu 安装boost 库
    ubuntu 16.04安装nVidia显卡驱动和cuda/cudnn踩坑过程
  • 原文地址:https://www.cnblogs.com/riddle/p/3231435.html
Copyright © 2020-2023  润新知