Eight Queens UVa 750

当时就觉得回溯法学的不是很好,在处理dp多状态问题前,温习一遍回溯法:把待求解的问题分成不太多的步骤,每个步骤只有不太多的选择,就可以考虑回溯法。

普通八皇后思路:从64格子中选8个格子,枚举的话一共有$C^{8}_{64}=4.426X10^{9}$解法,不爆才怪。
观察基本性质,每一行只能有一个皇后,所以最多只有$8!$种枚举可能。在实际操作的时候,状态树伸展肯定比这个值还要小,因为和之前的状态已经发生冲突,递归函数就不会再调用自身,而是返回上一层调用,这种现象被称为回溯(backtracking)。 回溯的关键在于回到上层调用时,要把改过去的状态改回来!否则原来状态被改变就不是原状态了。


代码:

 1 int tot;
 2 bool attacked[3][16];// 0 1 2分别表示是否被前面的皇后占据了列,左斜线,右斜线, 后面表示棋盘长度(8皇后有15斜)
 3 
 4 void search(int a){ //逐行搜索
 5     if(a==n){
 6         tot++; //递归边界,到了这里表示已经圆满完成
 7     }
 8     else{
 9         for(int i=0;i<n;i++){ //对于这一行,判断这一列能不能放
10             if(!attacked[0][i]&&!attacked[1][a+i]&&!attacked[2][n-a+i]){
11                 //尝试放置
12                 // cell[a] = i; //记录这行放置的列,用于打印
13                 attacked[0][i] = true;
14                 attacked[1][a+i] = true;
15                 attacked[2][n-a+i] = true;
16                 search(a+1);
17                 //调用完毕后一定要把状态改回来!
18                 //也就是说改变的状态是给之后的子状态用的,而不能影响同层其他结构
19                 attacked[0][i] = false;
20                 attacked[1][a+i] = false;
21                 attacked[2][n-a+i] = false;
22             }
23         }
24     }
25 }
26 
27 int main(){
28     cin>>n; //棋盘大小
29     tot = 0;
30     memset(attacked,0,sizeof(attacked));
31     
32     search(0);//从第0行开始
33     cout<<tot;
34 }
View Code

解题代码:

 1 //
 2 //  main.cpp
 3 //  8 QUEENS
 4 //
 5 //  Created by Yanbin GONG on 12/3/2018.
 6 //  Copyright © 2018 Yanbin GONG. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <stdio.h>
11 #include <string>
12 #include <string.h>
13 #define N 8
14 
15 int n;
16 bool vis[3][2*N];
17 int r, c, kase;
18 int ans[N];
19 
20 void search(int cur)
21 {
22     if (cur == N)
23     {
24         printf("%2d      ", ++kase);
25         for (int i = 0; i < N; i++)
26             printf("%d%s", ans[i]+1, (i==N-1) ? "\n" : " ");
27         return;
28     }
29     if (cur == c)  search(cur+1);
30     else
31     {
32         for (int i = 0; i < N; i++)
33             if (!vis[0][i] && !vis[1][cur-i+N] && !vis[2][cur+i])
34             {
35                 ans[cur] = i;
36                 vis[0][i] = vis[1][cur-i+N] = vis[2][cur+i] = 1;
37                 search(cur+1);
38                 vis[0][i] = vis[1][cur-i+N] = vis[2][cur+i] = 0;
39             }
40     }
41 }
42 
43 int main()
44 {
45     scanf("%d", &n);
46     while (n--)
47     {
48         scanf("%d%d", &r, &c);
49         r--;
50         c--;
51         memset(vis, 0, sizeof(vis));
52         vis[0][r] = 1;
53         vis[1][c-r+N] = 1;
54         vis[2][c+r] = 1;
55         ans[c] = r;
56         kase = 0;
57         printf("SOLN       COLUMN\n");
58         printf(" #      1 2 3 4 5 6 7 8\n\n");
59         search(0);
60         if (n)  printf("\n");
61     }
62     return 0;
63 }
View Code

 

转载于:https://www.cnblogs.com/cmbyn/p/8548865.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值