博弈问题,去模拟博弈过程,我走一步你走一步,走的都是对自己最有利的。用一个person变量来表示该谁走了,person=1是先手,person=0是后手。比较详细的注释写在最后一个想法里了。
第一个想法:纯暴力,用例2/8
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
using namespace std;
//person=1表示先手的人
int dfs(int sum, int n1, int n2, int n3,int person,int sum1,int sum2)
{
int min1 = min(n1, min(n2, n3));
if (sum < min1)
{
if (sum1 % 2 == 1&&sum2%2!=1)
{
return 1;
}
if (sum2 % 2 == 1 && sum1 % 2 != 1)
{
return -1;
}
return 0;
}
if (person == 1)
{
int a = 2, b = 2, c = 2;
if (sum >= n1)
{
a = dfs(sum - n1, n1, n2, n3, !person, sum1 + n1, sum2);
}
if (sum >= n2)
{
b = dfs(sum - n2, n1, n2, n3, !person, sum1 + n2, sum2);
}
if (sum >= n3)
{
c = dfs(sum - n3, n1, n2, n3, !person, sum1 + n3, sum2);
}
//cout << sum << " " << person << " " << sum1 << " " << sum2 << " a:"<<a<<" b:"<<b<<" c:"<<c << endl;
if (a == 1 || b == 1 || c == 1)
{
return 1;
}
else if ((a == 0&&a!=2) || (b==0&&b!=2) || (c==0&&c!=2))
{
return 0;
}
else
{
return -1;
}
}
else
{
int a = 2, b = 2, c = 2;
if (sum >= n1)
{
a = dfs(sum - n1, n1, n2, n3, !person, sum1, sum2+n1);
}
if (sum >= n2)
{
b = dfs(sum - n2, n1, n2, n3, !person, sum1, sum2+n2);
}
if (sum >= n3)
{
c = dfs(sum - n3, n1, n2, n3, !person, sum1, sum2+n3);
}
//cout << sum << " " << person << " " << sum1 << " " << sum2 << " a:" << a << " b:" << b << " c:" << c << endl;
if (a == -1 || b == -1 || c == -1)
{
return -1;
}
else if ((a == 0 && a != 2) || (b == 0 && b != 2) || (c == 0 && c != 2))
{
return 0;
}
else
{
return 1;
}
}
}
int main()
{
int n1, n2, n3;
cin >> n1 >> n2 >> n3;
vector<char>ans;
for (int i = 0; i < 5; i++)
{
int x = 0;
cin >> x;
int tmp = dfs(x, n1, n2, n3, 1, 0, 0);
if (tmp == 1)
{
ans.push_back('+');
}
else if (tmp == 0)
{
ans.push_back('0');
}
else
{
ans.push_back('-');
}
}
for (int i = 0; i < 5; i++)
{
cout << ans[i] << " ";
}
return 0;
}
第二个想法:备忘录剪枝,用例4/8
纯暴力过的用例太少,就想到了这个状态可能会有重复,用备忘录去重。
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
using namespace std;
//person=1表示先手的人
class memo
{
public:
int sum;
int person;
int sum1;
int sum2;
int res;
memo(int a, int b, int c, int d, int e)
{
sum = a;
person = b;
sum1 = c;
sum2 = d;
res = e;
}
};
vector<memo>memory;
int dfs(int sum, int n1, int n2, int n3,int person,int sum1,int sum2)
{
int min1 = min(n1, min(n2, n3));
for (int i = 0; i < memory.size(); i++)
{
if (sum == memory[i].sum && person == memory[i].person && sum1 == memory[i].sum1 && sum2 == memory[i].sum2)
{
return memory[i].res;
}
}
if (sum < min1)
{
if (sum1 % 2 == 1&&sum2%2!=1)
{
memo m(sum, person, sum1, sum2,1);
memory.push_back(m);
return 1;
}
if (sum2 % 2 == 1 && sum1 % 2 != 1)
{
memo m(sum, person, sum1, sum2, -1);
memory.push_back(m);
return -1;
}
memo m(sum, person, sum1, sum2, 0);
memory.push_back(m);
return 0;
}
if (person == 1)
{
int a = 2, b = 2, c = 2;
if (sum >= n1)
{
a = dfs(sum - n1, n1, n2, n3, !person, sum1 + n1, sum2);
}
if (sum >= n2)
{
b = dfs(sum - n2, n1, n2, n3, !person, sum1 + n2, sum2);
}
if (sum >= n3)
{
c = dfs(sum - n3, n1, n2, n3, !person, sum1 + n3, sum2);
}
//cout << sum << " " << person << " " << sum1 << " " << sum2 << " a:"<<a<<" b:"<<b<<" c:"<<c << endl;
if (a == 1 || b == 1 || c == 1)
{
memo m(sum, person, sum1, sum2, 1);
memory.push_back(m);
return 1;
}
else if (a == 0 || b==0|| c==0)
{
memo m(sum, person, sum1, sum2, 0);
memory.push_back(m);
return 0;
}
else
{
memo m(sum, person, sum1, sum2, -1);
memory.push_back(m);
return -1;
}
}
else
{
int a = 2, b = 2, c = 2;
if (sum >= n1)
{
a = dfs(sum - n1, n1, n2, n3, !person, sum1, sum2+n1);
}
if (sum >= n2)
{
b = dfs(sum - n2, n1, n2, n3, !person, sum1, sum2+n2);
}
if (sum >= n3)
{
c = dfs(sum - n3, n1, n2, n3, !person, sum1, sum2+n3);
}
//cout << sum << " " << person << " " << sum1 << " " << sum2 << " a:" << a << " b:" << b << " c:" << c << endl;
if (a == -1 || b == -1 || c == -1)
{
memo m(sum, person, sum1, sum2, -1);
memory.push_back(m);
return -1;
}
else if (a == 0 || b == 0 || c == 0)
{
memo m(sum, person, sum1, sum2, 0);
memory.push_back(m);
return 0;
}
else
{
memo m(sum, person, sum1, sum2, 1);
memory.push_back(m);
return 1;
}
}
}
int main()
{
int n1, n2, n3;
cin >> n1 >> n2 >> n3;
vector<char>ans;
for (int i = 0; i < 5; i++)
{
int x = 0;
cin >> x;
int tmp = dfs(x, n1, n2, n3, 1, 0, 0);
if (tmp == 1)
{
ans.push_back('+');
}
else if (tmp == 0)
{
ans.push_back('0');
}
else
{
ans.push_back('-');
}
}
for (int i = 0; i < 5; i++)
{
cout << ans[i] << " ";
}
return 0;
}
第三个想法:优化备忘录,用例7/8(最后一个用例暂时想不到怎么优化了)
用了备忘录之后,过的用例还是很少。又想到了是因为每次找状态都要遍历一边存储状态的数组,所以又想到了用哈希表减少这部分的开销。
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
using namespace std;
//person=1表示先手的人
//vector容器里依次装入sum,person,sum1,sum2
map<vector<int>, int>map1;
int dfs(int sum, int n1, int n2, int n3, int person, int sum1, int sum2)
{
int min1 = min(n1, min(n2, n3));
vector<int>m1;
//判断如果这个状态已经来过了就直接返回值。
m1.push_back(sum); m1.push_back(person); m1.push_back(sum1); m1.push_back(sum2);
if (map1.find(m1) != map1.end())
{
return map1[m1];
}
//结束状态,也就是拿不了了
if (sum < min1)
{
if (sum1 % 2 == 1 && sum2 % 2 != 1)
{
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = 1;
return 1;
}
if (sum2 % 2 == 1 && sum1 % 2 != 1)
{
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = -1;
return -1;
}
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = 0;
return 0;
}
//person=1,先手
if (person == 1)
{
int a = 2, b = 2, c = 2;
//将三种可能的拿法全试一次
if (sum >= n1)
{
a = dfs(sum - n1, n1, n2, n3, !person, sum1 + n1, sum2);
}
if (sum >= n2)
{
b = dfs(sum - n2, n1, n2, n3, !person, sum1 + n2, sum2);
}
if (sum >= n3)
{
c = dfs(sum - n3, n1, n2, n3, !person, sum1 + n3, sum2);
}
//只要有一种能赢就返回1,我就走那能赢的一步就可以了。
if (a == 1 || b == 1 || c == 1)
{
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = 1;
return 1;
}
else if (a == 0 || b == 0 || c == 0)
{
//已经赢不了了,找可以平局的情况
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = 0;
return 0;
}
else
{
//也平不了了,怎么走都是输才会返回-1
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = -1;
return -1;
}
}
else//person=0后手
{
int a = 2, b = 2, c = 2;
if (sum >= n1)
{
a = dfs(sum - n1, n1, n2, n3, !person, sum1, sum2 + n1);
}
if (sum >= n2)
{
b = dfs(sum - n2, n1, n2, n3, !person, sum1, sum2 + n2);
}
if (sum >= n3)
{
c = dfs(sum - n3, n1, n2, n3, !person, sum1, sum2 + n3);
}
//对于后手来说赢得情况就是返回-1
if (a == -1 || b == -1 || c == -1)
{
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = -1;
return -1;
}
else if (a == 0 || b == 0 || c == 0)
{
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = 0;
return 0;
}
else
{
vector<int>m;
m.push_back(sum); m.push_back(person); m.push_back(sum1); m.push_back(sum2);
map1[m] = 1;
return 1;
}
}
}
int main()
{
int n1, n2, n3;
cin >> n1 >> n2 >> n3;
vector<char>ans;
for (int i = 0; i < 5; i++)
{
int x = 0;
cin >> x;
int tmp = dfs(x, n1, n2, n3, 1, 0, 0);
if (tmp == 1)
{
ans.push_back('+');
}
else if (tmp == 0)
{
ans.push_back('0');
}
else
{
ans.push_back('-');
}
}
for (int i = 0; i < 5; i++)
{
cout << ans[i] << " ";
}
return 0;
}