F
似乎该博弈了!
题目描述
nova君陷入了困境,因为他无法在PS4游戏上凭借操作战胜对手。机智如他,只好和对手博弈了!
nova君拿出的方案和以往有些不一样,他说:“你可以决定石子数量和石子的取法,我来决定先后手,这样非常公平。”他的对手觉得nova君说的有道理,于是不仅决定了每局的石子数量,还给出了k个数字,表示每次可以任意取走数量等同于这k个数字中一个的石子,k中一定有一个为1。先取完者为胜。
现在很急很关键,快帮nova君看看他到底应该先手还是后手才能战胜对手。
输入
每组测试数据两行。
第一行两个整数n和k,第二行k个整数,意义如题目描述。
N<=100000,k<=15
输出
对于每组数据,输出一行,为nova应该采取的先后手 sente \ gote
输入样例
4 3
1 2 3
1 1
1
输出样例
gote
sente
解题思路:给定n个石头,和k种去除石头的方式,每种方式可以去除一定量的石头, 现在Sente(简称S),gote(简称O),S先手,O后手,每次每个人能选择一种去除石头的方式,谁去除最后一堆谁就赢了。要求出必胜之人是谁。
分析:
1.用一个dp数组记录,对于先手者能取到的记录为1,后手者为0.
2.初始dp数组都为0,遍历1到n,如果dp[i]为0,说明上一手是后手取得,这样先手就能取,把dp[i]变为1,由于是从1到n,这样每个状态记录时,前面的都已经记录好了,所以是可行的.
3.这样最后只需要判断dp[n]是1,还是0,就可以判断是先手胜还是后手胜了。
状态转移方程为:if (i - mjmj[j] >= 0 && !dp[i - mjmj[j]]) dp[i] = 1.
给出代码:
1 #include <bits/stdc++.h> 2 #define MAX 1000010 3 int dp[MAX],mjmj[15]; 4 5 int n,m,i,j; 6 int main() 7 { 8 while(~scanf("%d",&n)) 9 { 10 memset(dp,0,sizeof(dp)); 11 scanf("%d",&m); 12 for (i=0; i<m; i++) 13 { 14 scanf("%d",&mjmj[i]); 15 } 16 for (i=1;i<=n;++i) 17 { 18 for (j=0;j<m;++j) 19 { 20 if (i-mjmj[j]>=0&&!dp[i-mjmj[j]]) 21 { 22 dp[i]=1; 23 break; 24 } 25 } 26 } 27 if (dp[n]) 28 printf("sente\n"); 29 else 30 printf("gote\n"); 31 } 32 return 0; 33 }