18.5.25 深搜作业

A:棋盘问题

描述

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。输入输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
输出对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

样例输入

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

样例输出

2
1

来源

蔡错@pku

 1 #include <iostream>
 2 #include <string>
 3 #include <cstdio>
 4 #include <memory.h>
 5 #include <map>
 6 #include <math.h>
 7 using namespace std;
 8 const int maxn =15;
 9 int hangput[maxn], lieput[maxn],chess[maxn][maxn];
10 char thisline[maxn];
11 int n, k, sum=0;
12 
13 void solve(int hang,int num) {
14     if (num == 0)
15     {
16         sum++;
17         return;
18     }
19         for(int j=1;j<=n;j++)
20             if (chess[hang][j] && !lieput[j])
21             {
22                 //place the chess
23                 if (num - 1 == 0)
24                     sum++;
25                 else
26                 {
27                     lieput[j] = 1;
28                     for (int i = hang + 1; i <= n - num + 2; i++)
29                         solve(i, num - 1);
30                     lieput[j] = 0;
31                 }
32             }
33 }
34 
35 void init() {
36     while (scanf("%d%d", &n, &k) && (n != -1 || k != -1)) {
37         sum = 0;
38         for (int i = 1; i <= n; i++)
39             for(int j=1;j<=n;j++)
40         {
41                 char ch;
42                 cin >> ch;
43                 if (ch == '#')
44                     chess[i][j] = 1;
45                 else chess[i][j] = 0;
46         }
47         for (int i = 1; i <= n - k + 1; i++)
48             solve(i, k);
49         printf("%d\n", sum);
50     }
51 }
52 
53 int main()
54 {
55     init();
56     return 0;
57 }
View Code

比较水,和后面一道形成了鲜明的对比

B:生日蛋糕

描述

7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
(除Q外,以上所有数据皆为正整数)
输入有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。输出仅一行,是一个正整数S(若无解则S = 0)。

样例输入

100
2

样例输出

68

提示

圆柱公式
体积V = πR2H
侧面积A' = 2πRH
底面积A = πR2
来源

Noi 99

 1 #include <iostream>
 2 #include <string>
 3 #include <cstdio>
 4 #include <memory.h>
 5 #include <algorithm>
 6 #include <math.h>
 7 using namespace std;
 8 const int maxn =15;
 9 int n,m,smin=999999;
10 const int maxnum = 9999999;
11 
12 void solve(int v,int k,int topr,int toph,int S) {
13     if (k == 0)
14     {
15         if (v == 0)
16             smin=min(S,smin);
17         return;
18     }
19     if (S + 2 * (v / topr) > smin)
20         return;
21     if ((unsigned)(topr - 1)*(unsigned)(topr - 1)*(unsigned)(toph - 1)*k < v)
22         return;
23     int topv = v - k * (k - 1) / 2,_min=maxnum;
24     for(int i=topr-1;i>=k;i--)
25         for (int j = k; j < toph; j++)
26         {
27             int _v = i * i*j;
28             if (_v*k < v)
29                 continue;
30             if (_v<v / k)
31                 continue;
32             if (_v > topv)
33                 continue;
34             int s = 2 * i*j;
35             if (s + k*(k-1)/2 > smin)
36                 continue; 
37             int sums = s + S;
38             if (k == m)
39                 sums+=i*i;
40             solve(v - _v, k - 1, i, j, sums);
41         }
42 }
43 
44 void init() {
45     scanf("%d%d", &n, &m);
46     int maxr = sqrt(n);
47     solve(n, m, maxr, n,0);
48     printf("%d\n", smin);
49 }
50 
51 int main()
52 {
53     init();
54     return 0;
55 }
View Code

一开始我把深搜函数设置为返回S值,如果不能就返回一个超大值……果断TLE。后来想是不是这样每次调用min太慢了,改成了void,直接在函数中在边界条件做判断取最小值,快了巨多……

一开始我的剪枝全部在循环内部,我也在想这样剪枝是不是有点弱……果然太弱……

其实……剪枝只要一个就可以了……就是那个 if (S + 2 * (v / topr) > smin) (最优化剪枝)

最难想,但剪掉的最多

其他……感觉不是特别有用……

然后 (unsigned)(topr - 1)*(unsigned)(topr - 1)*(unsigned)(toph - 1)*k < v 不加 unsigned 会WA,因为会出现溢出。感谢洛谷提供的数据TUT

但是那个条件好像没什么用……

猜你喜欢

转载自www.cnblogs.com/yalphait/p/9087920.html