蓝桥杯 约数倍数选卡片
Posted 王宜鸣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯 约数倍数选卡片相关的知识,希望对你有一定的参考价值。
思路:
搜索、博弈论。
实现的时候一个剪枝是从较大的数开始选,因为较大的数约数或倍数少一些,搜索的层数少。
还可以预处理出每个数的约数和倍数,这样搜索的时候不用扫描所有的数。
实现:
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <string> 5 #include <cstring> 6 #include <sstream> 7 #include <vector> 8 #include <algorithm> 9 using namespace std; 10 11 const int MAXN = 105; 12 int a[MAXN], b[MAXN], m = 0; 13 vector<int> ok[MAXN]; 14 15 bool check(int x, int y) 16 { 17 int p = min(x, y); 18 int q = max(x, y); 19 return !(q % p); 20 } 21 22 void init() 23 { 24 for (int i = 1; i < MAXN; i++) 25 { 26 if (a[i]) 27 { 28 for (int j = 1; j < MAXN; j++) 29 { 30 if (a[j] && check(i, j)) 31 ok[i].push_back(j); 32 } 33 } 34 } 35 } 36 37 bool dfs(int last) 38 { 39 for (int i = ok[last].size() - 1; i >= 0; i--) 40 { 41 int tmp = ok[last][i]; 42 if (a[tmp]) 43 { 44 a[tmp]--; 45 bool res = dfs(tmp); 46 a[tmp]++; 47 if (!res) 48 return true; 49 } 50 } 51 return false; 52 } 53 54 int main() 55 { 56 string x; 57 int t; 58 stringstream s; 59 getline(cin, x); 60 s << x; 61 while (s >> t) a[t]++; 62 init(); 63 s.clear(); 64 getline(cin, x); 65 s << x; 66 while (s >> b[m++]); 67 m--; 68 sort(b, b + m); 69 int * end = unique(b, b + m); 70 bool flag = true; 71 for (int i = 0; i < end - b; i++) 72 { 73 a[b[i]]--; 74 bool res = dfs(b[i]); 75 a[b[i]]++; 76 if (!res) 77 { 78 cout << b[i] << endl; 79 flag = false; 80 break; 81 } 82 } 83 if (flag) 84 cout << -1 << endl; 85 return 0; 86 }
总结:
必败点:前一个选手将取胜的位置称为必败点。
必胜点:下一个选手将取胜的位置称为必胜点。
必胜点和必败点属性:
(1)所有终结点是必败点。
(2)从任何必胜点操作,至少有一种方法可以进入必败点。
(3)无论如何操作,从必败点都只能进入必胜点。
可以采用递归或递推实现。
注意函数参数的值传递的过程。
回溯的时候不要影响标记状态的全局变量,要及时归位。
以上是关于蓝桥杯 约数倍数选卡片的主要内容,如果未能解决你的问题,请参考以下文章