CPU消耗 < 1000ms
博弈论的理论就是,对手的必败态就是我的必胜态。需要注意的是只要某个选择可以导致对手出现必败态,则这个选择就是正确的,可以直接返回;而当我所有选择走了一遍之后,发现并没有返回,即并没有对手的必败态,才可以说明这是我的必败态。
开始只过了40%,原因是冗余变量多,最主要的问题就是在选择某一张卡片改变当前局面的时候,又重新选择了一遍它的约数倍数,而由于使用的是数组,所以就是按照整个规模即n来跑的循环,超时。
看了某神的代码后- - 嗯。可以通过vector事先将所有在范围内的数的约数倍数都存好,当选择了某一张卡片时,直接取到它对应的vector即可。而且数组也不用开那么多,最初的初始范围数组根本不必要,只需要num数组统计每一个数出现的次数即可。我开始的思想是从1到n遍历一遍,还要判断这个i出没出现过,还要判断它出现次数。。。然后选择了某个i还要重新赋值它的约数倍数。。。冗余变量和冗余循环都很多。精简以后可以每次只从可能的choice里边选,选择了以后直接改变它的出现次数变量,然后递归循环时新的可选择数也可以通过事先保存的vector取出。
tle:
#include
#include
int a[105], num[105], n, f = 0, ans;
int dfs(int sn, int flag[])
{
int i, j, tsn = 0, choose, f1[105];
if(sn == 0)
return -1;
for(i = 0 ; i < n ; i++)//全部卡片
{
if(a[i] != 0 && flag[a[i]])//没有被选走,并且还在可选择的范围内
{
choose = a[i];
a[i] = 0;//被选走了
for(j = 0 ; j < n ; j++)//修改目前可选择的
{
f1[a[j]] = 0;
if(a[j] != 0 && (a[j] % choose == 0 || choose % a[j] == 0))
{
f1[a[j]]++;
tsn++;
}
}
int temp = dfs(tsn, f1);
a[i] = choose;//开始时这个语句放的位置不对,放在了if之后,这样的话如果返回了一个必败局面,则整个a数组都给改了
if(temp == -1)
{
ans = choose;
return 1;
}
}
}
return -1;
}
int main()
{
char c;
int flag[105];
int i = 0, j, sum = 0, x;
memset(flag, 0, sizeof(flag));
while(1)
{
scanf("%d", &a[i]);
num[a[i]]++;
i++;
c = getchar();
if(c == '\n')
break;
}
while(1)
{
scanf("%d", &x);
sum++;
flag[x]++;
c = getchar();
if(c == '\n')
break;
}
n = i;
int temp = dfs(sum, flag);
if(temp == 1)
printf("%d\n", ans);
else
printf("-1\n");
return 0;
}
#include
#include
#include
#include
using namespace std;
vector choice;
vector table[105];
int a[105], num[105], n, f = 0, ans;
int dfs(int choose)
{
int i, new_choose, t;
//if(sn == 0)可以去掉了,因为如果当前的choose已经没有可以选择的约数了,下边这个循环是不会进行的,也会走到返回-1那一步
// return -1;
for(i = table[choose].size() - 1 ; i >= 0 ; i--)
{
new_choose = table[choose][i];
if(num[new_choose])
{
num[new_choose]--;
t = dfs(new_choose);
num[new_choose]++;
if(t == -1)
return 1;
}
}
return -1;
}
int main()
{
char c;
int i = 0, j, sum = 0, x, new_choose, t;
while(1)
{
scanf("%d", &x);
num[x]++;//出现次数
i++;
c = getchar();
if(c == '\n')
break;
}
while(1)
{
scanf("%d", &x);
sum++;
choice.push_back(x);
c = getchar();
if(c == '\n')
break;
}
sort(choice.begin(), choice.end());
for(i = 1 ; i < 101 ; i++)//把每个数的约数倍数都事先存下来,要注意这里是倒序的
{
if(num[i])
{
for(j = 1 ; j < 101 ; j++)
{
if(num[j] && (i % j == 0 || j % i == 0))
table[i].push_back(j);
}
}
}
for(i = 0 ; i < choice.size() ; i++)
{
new_choose = choice[i];
num[new_choose]--;
t = dfs(new_choose);
num[new_choose]++;
if(t == -1)
{
printf("%d\n", new_choose);
return 0;
}
}
printf("-1\n");
return 0;
}