原题链接:蓝桥杯历届试题-约数倍数选卡片
解题思路:
基本的博弈都可以用递归来求解,这道题由于想不到有效解法,则用 递归+优化
1. 尝试所有走法,把局面交给对手,如果对手的局面是必输,则当前局面必胜;
2. 尝试所有走法后,还是赢不了那 当前局面比输
递归思路:
dfs(局面s){
尝试走一步s变成s1,把s1交给对手
如果存在一个s1局面必输:返回赢了;
返回必输;
}
不优化 只有50%成绩
优化思路:1.优先当前可选的数字大的卡片(数字越大,则约倍数在100内越少,所以递归的层数就越少)
2.常数优化,递归之前预处理每张卡片的下一次可选卡片集合
注意事项:
这个C语言网不知为什么代码AC不了一直超时17%,我去蓝桥杯官网提交了两次都600msAC了

参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
#define _for(i,a,b) for(int i=a;i<b;i++)
#define _unfor(i,a,b) for(int i=a;i>=b;i--)
#define mset(a,val,n) for(int i=0;i<n;i++)a[i]=val;
#define FO freopen("out.txt","w",stdout)
#define RI(a) scanf("%d",&a)
using namespace std;
typedef long long LL;
int a[111],b[111],c='A';
vector<int> G[111];
int ri(){
int x=0;
while(!isdigit(c))if((c=getchar())=='\n')return 0;
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x;
}
int dp(int i){
if(!a[i])return 0;
a[i]--;
int len=G[i].size();
_for(k,0,len){
int j=G[i][k];
if((!(i%j)||!(j%i))&&a[j])
if(!dp(j)){a[i]++;return 1;}
}
a[i]++;
return 0;
}
int main(){
int x;
while(x=ri()){
a[x]++;
if(c=='\n')break;
}
//预处理
_for(i,1,101)
_unfor(j,100,1)if((!(i%j)||!(j%i))&&a[j])
G[i].push_back(j);
//
while(x=ri()){
b[x]++;
if(c=='\n')break;
}
_for(i,1,101)if(b[i])
if(!dp(i)){printf("%d\n",i);return 0;}
printf("%d\n",-1);
return 0;
}0.0分
5 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复