ZOJ1827_The Game of 31

这是一个比较经典的博弈题目,今年网赛好像是南京赛上有一个类似的题目。

这种题目是没有一定公式或者函数的,需要自己dp或者搜索解决。

题意为分别给你4张写有1,2,3,4,5,6的卡片共24张,每次轮流拿一张卡片,且所有被拿过的卡片的总和不能超过31,谁无法拿出卡片就fail。

首先对于每种卡片一共可能有5中存在情况,所以六张卡片一共有5^6种情况,同时我们保存当前拿到的卡片的数量的和,然后记忆化搜就行了。

记得每次取最优,同时还要注意除掉拿过的牌,当前是谁第一个拿牌哦。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxn 20000
 5 using namespace std;
 6 
 7 int dig[7],f[35][maxn];//f[i][j]表示和为i,状态为j的时候是否是必胜状态,如果是的话,值为1,否则值为-1.0表示没有搜过。j用的是5进制,这里比较巧妙。
 8 char s[50];
 9 
10 int dfs(int tot,int cur)
11 {
12     if (f[tot][cur]!=0) return f[tot][cur];
13     for (int i=1; i<=6; i++)
14     {
15         if (tot+i>31) continue;
16         if ((cur/dig[i])%5==0) continue;
17         if (dfs(tot+i,cur-dig[i])==-1)
18         {
19             return f[tot][cur]=1;
20         }
21     }
22     return f[tot][cur]=-1;
23 }
24 
25 int main()
26 {
27     int ans,cur,tot,tep;
28     dig[1]=1;
29     dig[0]=4;
30     for (int i=2; i<=6; i++) dig[i]=5*dig[i-1],dig[0]+=4*dig[i];//五进制预处理。
31     while (gets(s))
32     {
33         memset(f,0,sizeof f);
34         cur=dig[0],tot=0;
35         for (int i=0; s[i]; i++)
36         {
37             tep=s[i]-'0';
38             tot+=tep;
39             cur-=dig[tep];
40         }
41         if (strlen(s)&1) ans=-1; else ans=1;
42         ans*=dfs(tot,cur);
43         if (ans==-1) printf("%s B
",s);
44             else printf("%s A
",s);
45     }
46     return 0;
47 }
如有转载,请注明出处(http://www.cnblogs.com/lochan)
原文地址:https://www.cnblogs.com/lochan/p/3375066.html