21天零基础入门ACM
21天零基础入门ACM之 第3天
博弈论(sg函数)
题意:
链接:https://ac.nowcoder.com/acm/problem/14388
sg函数
这道题很简单,一看就是巴什博弈,但是,我现在是借助这道题简单的说下sg函数。想要细学sg函数,可以看看这篇博客(https://blog.youkuaiyun.com/strangedbly/article/details/51137432)
先附上sg函数的代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int f[N],sg[N],ha[N]; //f存可取的方法
void getSG(int n,int k) //n是石子的数量 k是有多少种取法
{
int i,j;
memset(sg,0,sizeof(sg));
for(i=1;i<=n;i++)
{
memset(ha,0,sizeof(ha));
for(j=1;f[j]<=i&&j<=k;j++)
ha[sg[i-f[j]]]=1;
for(j=0;j<=n;j++)
{
if(ha[j]==0)
{
sg[i]=j;
break;
}
}
}
}
int main(){
int T,n,k;
while(cin>>n>>k){
for(int i=1;i<=k;i++){
f[i]=i;
}
getSG(n,k);
for(int i=1;i<=n;i++){
cout<<sg[i]<<" ";
}
if(sg[n]!=0) cout<<"first"<<endl;
else cout<<"second"<<endl;
}
return 0;
}
解析
sg函数的复杂度较高,主要可以用来打表找规律,比如这道题,若是输入
n = 10,m = 3,输出结果是:
为0处的应该都输出first,否则输出second,由此找到规律 n%(m+1)==0.
得出正解代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,m;
while(cin>>n>>m){
if(n%(m+1)!=0) cout<<"first"<<endl;
else cout<<"second"<<endl;
}
return 0;
}
题目2:
链接:https://ac.nowcoder.com/acm/problem/14619
思路
这道题的原型就是 NIM游戏 。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=1e5+7;
int a[N];
int main(){
int t;
cin>>t;
while(t--){
int n,m,ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
if(i!=m)
ans=ans^a[i];
}
if(ans<a[m])cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
题目3
链接:https://ac.nowcoder.com/acm/problem/15065
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=1e5+7;
int main(){
int n,m;
while(cin>>n){
if(n>2) cout<<"XiaoKe"<<endl;
else cout<<"XiaoNiu"<<endl;
}
return 0;
}
小总结
说到底,博弈找的就是必胜态和必败态,及他们之间的转化关系。可以先从简单的情况出发,找出必胜和必败的简单情况,和他们之间的转化关系。然后,在由浅入深推断出符合整个题目的一般规律。
另外,很多题目都和奇偶有关,可以往这个方向思考思考。