【Luogu】【关卡2-9】带有技巧的搜索(2017年10月)

任务说明:这里的搜索不仅包含了dfs和bfs,还包括剪枝、记录等技巧以加快速度。

[USACO06FEB]数字三角形Backward Digit Su…
滑雪
吃奶酪
靶形数独

P1118 [USACO06FEB]数字三角形Backward Digit Su…

有这么一个游戏:写出一个1~N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置。

最后得到16这样一个数字。

现在想要倒着玩这样一个游戏,如果知道N,知道最后得到的数字的大小sum,请你求出最初序列a[i],为1~N的一个排列。若答案有多种可能,则输出排序最小的那一个。

解答:第一次我想直接next_permutation,然后在嵌套循环计算顶层数字,结果TLE了好几个点。

后来看了题解,大家都说的杨辉三角,我还是没懂。专门搜索了题解才看懂。

最后的结果其实是一个杨辉三角。(拿样例来说,第4层的杨辉三角是1 3 3 1; 1∗3+3∗1+3∗2+1∗4=16)

然后知道杨辉三角怎么用了之后,直接dfs求全排列,如果超过了sum值就回溯。 

 1 #include <bits/stdc++.h>
 2 #include <string>
 3 using namespace std;
 4 
 5 int n, sum;
 6 int yanghuisanjiao[20][20] = {0};
 7 int used[20] = {0};
 8 
 9 void print(vector<int>& vec, std::string& strDes) {
10     printf("%s: ", strDes.c_str());
11     for (int i = 0; i < vec.size(); ++i) {
12         printf("%d ", vec[i]);
13     }
14     printf("
");
15 }
16 
17 void print(vector<int>& vec) {
18     for (int i = 0; i < vec.size(); ++i) {
19         printf("%d ", vec[i]);
20     }
21     printf("
");
22 }
23 
24 bool dfs(int level, vector<int>& permutation, int cal_sum, int idx) {
25     if (level == n + 1) {
26         if (cal_sum == sum) {
27             print(permutation);
28             return true;
29         }
30         return false;
31     }
32     for (int i = 0; i < n; ++i) {
33         if (!used[i+1]) {
34             permutation[idx] = i + 1;
35             used[i+1] = 1;
36             //如果求和大于sum,就剪枝
37             if (cal_sum + yanghuisanjiao[n-1][idx] * permutation[idx]  > sum) {
38                 used[i+1] = false;
39                 return false;
40             }
41             bool ans = dfs(level + 1, permutation, cal_sum + yanghuisanjiao[n-1][idx] * permutation[idx], idx + 1);
42             if (ans == true) {
43                 return true;
44             }
45             used[i+1] = 0;
46         }
47     }
48     //找到最后也没找到, 就return false
49     return false;
50 }
51 
52 
53 int main() {
54     cin >> n >> sum;
55 
56     //[1]计算杨辉三角
57     for (int i = 0; i < n ; ++i) {
58         for (int j = 0; j <= i; ++j) {
59             if (j == 0 || j == i ) {
60                 yanghuisanjiao[i][j] = 1;
61             }
62             else {
63                 yanghuisanjiao[i][j] = yanghuisanjiao[i-1][j-1] + yanghuisanjiao[i-1][j];
64             }
65         }
66     }
67 
68     //[2]深搜求全排列
69     vector<int> permutation(n, 0);
70     dfs(1, permutation, 0, 0);
71     return 0;
72 }
View Code

P1433 吃奶酪

房间里放着n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处。

输入:第一行一个数n (n<=15),接下来每行2个实数,表示第i块奶酪的坐标。两点之间的距离公式=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

输出:一个数,表示要跑的最少距离,保留2位小数。

题解:显然贪心不行。那么只能搜索每个点的顺序,求最小值的距离。

 1 //这个题目最后也是90分,第五个点TLE,没想明白为啥
 2 #include<bits/stdc++.h>
 3 #include<unistd.h>
 4 #include <sys/time.h>
 5 using namespace std;
 6 
 7 typedef pair<double, double> P;
 8 int n;
 9 
10 double ans = DBL_MAX;
11 int addx[4] = {0, -1, 0, 1};
12 int addy[4] = {-1, 0, 1, 0};
13 
14 void print(vector<vector<double>> vec) {
15     printf("===============debug============
");
16     for (int i = 0; i < vec.size(); ++i) {
17         for(int j = 0; j < vec.size(); ++j) {
18             printf("%.2f ", vec[i][j]);
19         }
20         printf("
");
21     }
22     printf("===============end==============
");
23 }
24 
25 void dfs(const vector<P>& coor, const double dis[16][16], vector<int>& used, int level, double tmpans, int pre) {
26     if (tmpans >= ans) {
27         return;
28     }
29     if (level == coor.size()) {
30         if (ans > tmpans) { ans = tmpans;}
31         return;
32     }
33     for(int i = 1; i < coor.size(); ++i) {
34         double temp = dis[pre][i] + tmpans;
35         if (!used[i] && temp < ans) {
36             used[i] = 1;
37             dfs(coor, dis, used, level+1, temp, i);
38             used[i] = 0;
39         }
40     }
41 }
42 
43 int main() {
44         struct timeval tv;
45         gettimeofday(&tv, NULL);
46         printf("%ld
", tv.tv_sec);
47     scanf("%d", &n);
48     vector<P> coor(n + 1);
49     coor[0] = make_pair(0.0, 0.0);
50     for(int i = 1; i <= n; ++i){
51         double x, y;
52         scanf("%lf %lf", &x, &y);
53         coor[i] = make_pair(x, y);
54     }
55 
56     double dis[16][16] = {0.0};
57     for(int i = 0; i <= n; ++i) {
58         for(int j = i; j <= n; ++j) {
59             dis[i][j] = dis[j][i]
60             = sqrt((coor[i].first - coor[j].first)*(coor[i].first - coor[j].first)
61                 + (coor[i].second - coor[j].second)*(coor[i].second - coor[j].second));
62         }
63     }
64 
65     vector<int> use(n+1);
66     use[0] = 1;
67     dfs(coor, dis, use, 1, 0.0, 0);
68     printf("%.2f
", ans);
69         gettimeofday(&tv, NULL);
70         printf("%ld
", tv.tv_sec);
71     return 0;
72 }
View Code
原文地址:https://www.cnblogs.com/zhangwanying/p/7634741.html