A40909. 约数倍数选卡片问题描述闲暇时,福尔摩斯和华生玩一个游戏:在N张卡片上写有N个整数。两人轮流拿走一张卡片。要求下一个人拿的数字一定是前一个人拿的数字的约数或倍数。例如,某次福尔摩斯拿走的卡片上写着数字“6”,则接下来华生可以拿的数字包括:1,2,3, 6,12,18,24 ....当轮到某一方拿卡片时,没有满足要求的卡片可选,则该方为输方。请你利用计算机的优势计算一下,在已知所有卡片上的数字和可选…
填空题
困难
知识点
题目描述
约数倍数选卡片
问题描述
闲暇时,福尔摩斯和华生玩一个游戏:
在N张卡片上写有N个整数。两人轮流拿走一张卡片。要求下一个人拿的数字一定是前一个人拿的数字的约数或倍数。例如,某次福尔摩斯拿走的卡片上写着数字“6”,则接下来华生可以拿的数字包括:
1,2,3, 6,12,18,24 ....
当轮到某一方拿卡片时,没有满足要求的卡片可选,则该方为输方。
请你利用计算机的优势计算一下,在已知所有卡片上的数字和可选哪些数字的条件下,怎样选择才能保证必胜!
当选多个数字都可以必胜时,输出其中最小的数字。如果无论如何都会输,则输出-1。
输入格式
输入数据为2行。第一行是若干空格分开的整数(每个整数介于1~100间),表示当前剩余的所有卡片。
第二行也是若干空格分开的整数,表示可以选的数字。当然,第二行的数字必须完全包含在第一行的数字中。
输出格式
程序则输出必胜的招法!!
样例输入
2 3 6
3 6
样例输出
3
样例输入
1 2 2 3 3 4 5
3 4 5
样例输出
4
参考答案
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 105;
//num数组用于存放第一行输入的每一个数的出现次数 aa数组用于存放第二行先手可以先出的牌数
int num[MAXN],aa[MAXN];
vector<int> vec[MAXN]; //vec[i]用于存放在1和100之间并且在num数组中出现过的i的约数或者倍数
int ind;
bool Select(int k)
{
//这里必须要从vec[k].size()开始,如果从0开始会出现超时(这里不懂为啥超时。。。)
for(int i=vec[k].size()-1;i>=0;--i)
if(num[vec[k][i]])
{
num[vec[k][i]]--;
bool ok = Select(vec[k][i]);
num[vec[k][i]]++;
if(ok) return false;
}
return true;
}
int main()
{
int x;
while(true)
{
cin >> x;
num[x]++;
char ch = getchar();
if(ch == '\n') break;
}
while(true)
{
cin >> x;
aa[++ind] = x;
char ch = getchar();
if(ch == '\n') break;
}
//对aa数组排序,因为如果先手有必胜态,题目要求的是输出能产生必胜态的最小的数字
sort(aa+1,aa+ind+1);
//下面的循环两层必须都从1到100循环,因为不管是先手还是后手,拿到一张牌之后,都要依据vec来
//寻找此数的约数或是倍数。
for(int i=1;i<=100;++i)
for(int j=1;j<=100;++j)
if((i%j==0||j%i==0)&&num[j])
vec[i].push_back(j);
for(int i=1;i<=ind;++i)
{
if(num[aa[i]])
{
num[aa[i]]--; //此处表示先出首先出了aa[i]这张牌
//如果Select(aa[i])返回true,那么说明后手不管出了什么牌,都是必败的,那么此时就可以输出
//aa[i]并且结束程序
if(Select(aa[i]))
{
printf("%d\n",aa[i]);
return 0;
}
num[aa[i]]++; //回溯 这里表示先出aa[i]是必败的,那么判断下一种情况
}
}
printf("-1\n");
return 0;
}
上一题
下一题