抽签问题(不断优化)

问题描述:

假设存在n个签,通过抽取四次,如果四次抽取的和为m即胜利。

初始解:

 1 for(int a = 0; a < n; a++)
 2 {
 3     for(int b = 0; b < n; b++)
 4     {
 5         for(int c = 0; c < n; c++)
 6         {
 7             for(int d = 0; d < n; d++)
 8             {
 9                 if(k[a] + k[b] + k[c] + k[d] == m)
10                     f = true;
11             }
12         }
13     }
14 }

难度增加,将n的限制条件为1~1000,此时,四重循环明显复杂度过高,需改进算法。

上面所记载的程序的循环部分。最内侧关于d的循环所做的事就是

检查是否有d使得

通过对式子移项,就能得到另一种表达式

检查是否有d使得

就是说,检查数组k中所有元素,判断是否有

结合二分搜索进行求解,注意二分搜索前提为该数组排好序(可用c++自带的binary_serach)

 1 int n, m, k[MAX_N];
 2 
 3 bool binary_serach(int x)
 4 {
 5     int l = 0, r = n;
 6     while(r - 1 >= 1)
 7     {
 8         int i = (l + r) / 2;
 9         if(k[i] == x)
10             return true;
11         else if(k[i] < x)
12             l = i + 1;
13         else
14             r = i;
15     }
16     return false;
17 }
18 
19 void solve()
20 {
21     sort(k, k + n);
22     bool f = false;
23     for(int a = 0; a < n; a++)
24     {
25         for(int b = 0; b < n; b++)
26         {
27             for(int c = 0; c < n; c++)
28             {
29                 if(binary_serach(m - k[a] - k[b] - k[c]))
30                 {
31                     f = true;
32                 }
33             }
34         }
35     }
36     if(f)
37         cout << "Yes" << endl;
38     else
39         cout << "No" << endl;
40 }

 的算法

着眼于内层的两个循环

检查是否有c和d使得

这种情况并不能直接使用二分搜索。但是,如果预先枚举出所得的个数字并排好序,便可以利用二分搜索了。

 1 int n, m, k[MAX_N];
 2 int kk[MAX_N * MAX_N];
 3 bool binary_serach(int x)
 4 {
 5     int l = 0, r = n * n;
 6     while(r - 1 >= 1)
 7     {
 8         int i = (l + r) / 2;
 9         if(kk[i] == x)
10             return true;
11         else if(kk[i] < x)
12             l = i + 1;
13         else
14             r = i;
15     }
16     return false;
17 }
18 
19 void solve()
20 {
21     for(int c = 0; c < n; c++)
22     {
23         for(int d = 0; d < n; d++)
24         {
25             kk[c * n + d] = k[c] + k[d];
26         }
27     }
28     
29     sort(kk, kk + n * n);
30     for(int a = 0; a < n; a++)
31     {
32         for(int b = 0; b < n; b++)
33         {
34             if(binary_serach(m - k[a] - k[b]))
35             {
36                 f = true;
37             }
38         }
39     }
40     if(f)
41         cout << "Yes" << endl;
42     else
43         cout << "No" << endl;
44 }
原文地址:https://www.cnblogs.com/CZT-TS/p/8370635.html