第三次组队赛 (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
 2 #include<string.h>
 3 #include
 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:\n", 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("\n\n"); //要空一行
53             }
54         else printf("impossible\n\n"); //要空一行
55     }
56     return 0;
57 }

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

代码:      16ms  BFS

 1 #include
 2 #include
 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//找出最大值
47                 maxn=ans;
48             }
49         }
50     cout<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)
59         {
60             scanf("%d%d",&j,&k);
61             map[j][k]=1;
62         }
63         bfs();
64     }
65     return 0;
66 }

另一种方法:DFS      16MS

 1 #include
 2 #include<string.h>
 3 #include
 4 #include
 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)
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\n",MAX);
45     }
46     return 0;
47 }

 

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

代码:     0MS

 1 #include
 2 #include
 3 #include
 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=0 && hy=0 && hz'.' ||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//输入地图
50             for(j=0;j)
51                scanf("%s",a[i][j]);
52         for(i=0;i)
53           for(j=0;j)
54             for(k=0;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!\n");
65         else
66             printf("Escaped in %d minute(s).\n",number);
67     }
68     return 0;
69 }

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

代码:      15MS

 1 #include
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;i1;i++)
12          printf("%d+",b[i]);
13       printf("%d\n",b[g-1]);   //打出等式
14       return ;
15    }
16    int last=-1;
17    for(i=k;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)
35           scanf("%d",&a[i]);
36       printf("Sums of %d:\n",t);
37       dfs(0, 0, 0);
38       if(flag)
39         printf("NONE\n");
40    }
41 }

 另一份代码:    0ms

 1 #include 
 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("\n");
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:\n",t);
42         dfs(0,0);
43         if (!flag) printf("NONE\n");
44     }
45     return 0;
46 }

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

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

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

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

 1 #include
 2 #include
 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)
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\n",t);
35     }
36     return 0;
37 }

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

 1 #include
 2 #include
 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)
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\n",t);
42     }
43     return 0;
44 }

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

 1 #include 
 2 #include 
 3 #include 
 4 using namespace std;
 5 int n,x[15],sum,a[15];
 6 int place(int i)
 7 {
 8     for(int j=1;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\n",a[n]);
35     return 0;
36 }

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

如图:第三次组队赛 (DFS&BFS)_第1张图片

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

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

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

 1 #include 
 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\n", ans);
44     }
45     return 0;
46 }

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

代码:         31MS

 

 1 #include
 2 #include
 3 #include
 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=0 && hy=0 && hz'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)
55         {
56             for(j=0;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\n",quan);continue;}
67         bfs(z1,x1,y1);
68         if(number==0)
69             printf("NO ROUTE\n");
70         else
71             printf("%d %d\n",number+quan,number);
72     }
73     return 0;
74 }

 

转载于:https://www.cnblogs.com/riddle/p/3231435.html

你可能感兴趣的:(第三次组队赛 (DFS&BFS))