题目描述
闲暇时,福尔摩斯和华生玩一个游戏:
在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
资源约定:
峰值内存消耗 < 64M
CPU消耗 < 1000ms
思路:n最大为100,先用一个vector数组预处理出所有能选的牌,然后对第一步能出的所有牌排序后遍历,进行搜索,若有牌可以赢,直接输出并break。
注意:输入的时候用到了stringstream来处理字符串(头文件是ssstream),具体的可以百度一下。
#include<iostream>
#include<sstream>
#include<vector>
#include<algorithm>
using namespace std;
#define N 100005
int num[N];
int n;
vector<int> b;
vector<int> a[105];
int dfs(int x) //在上一张选x的情况下
{
for(int i=a[x].size()-1;i>=0;i--) //遍历选了x之后能选的牌
{
if(num[a[x][i]])
{
num[a[x][i]]--;
int t=dfs(a[x][i]); //若我选了这张牌以后对方会输,返回1(自己可以赢)
num[a[x][i]]++;
if(t==-1)
return 1;
}
}
return -1; //若无牌可选或者选任一能选的牌之后对方都会赢,返回-1(自己会输)
}
int main()
{
string s;
int x;
getline(cin,s);
stringstream in(s);
while(in>>x)
{
num[x]++;
}
int ans=-1;
getline(cin,s);
stringstream iin(s);
while(iin>>x)
{
b.push_back(x);
}
for(int i=1;i<=100;i++)
{
if(num[i])
{
num[i]--;
for(int j=1;j<=100;j++)
{
if(num[j] && (i%j==0 || j%i==0))
a[i].push_back(j);
}
num[i]++;
}
}
sort(b.begin(),b.end()); //先排序再遍历,因为如果有两张牌都能赢,需输出小的那个
for(int i=0;i<b.size();i++)
{
num[b[i]]--;
int t=dfs(b[i]);
if(t==-1)
{
cout<<b[i]<<endl;
return 0;
}
num[b[i]]++;
}
cout<<"-1"<<endl;
return 0;
}