标签:英语四级 判断 问题 ons eve 计算 ace bool 初始化
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1847
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int n; 6 while(cin>>n){ 7 if(n%3)cout<<"Kiki"<<endl;//不是3的倍数,先手必赢 8 else cout<<"Cici"<<endl;//是3的倍数,后手必赢 9 } 10 return 0; 11 }
这题还可以用SG值解决,所谓的SG值就是记录当前状态是N是P的具体值,N-position表示必赢状态(其SG值不为0),P-position表示必输状态(其SG值为0)。下面介绍怎么求SG值:首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示不属于mex这个集合的最小非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数g如下:g(n)=mex{ g(m) | m是n的后继 },这里的g(n)即sg[n]
拿本题的栗子来讲:首先有sg[0]=0,f[]={1,2,4...};(f数组存放可以抓走扑克牌的张数,并且按升序存放)
当n=1时,先手可以抓走1-f{1}张牌,剩余{0}张,mex{sg[0]}={0},故sg[1]=1;
当n=2时,先手可以抓走2-f{1,2}张牌,剩余{1,0}张,mex{sg[1],sg[0]}={1,0},故sg[2]=2;
当n=3时,先手可以抓走3-f{1,2}张牌,剩余{2,1}张,mex{sg[2],sg[1]}={2,1},故sg[3]=0;
当n=4时,先手可以抓走4-f{1,2,4}张牌,剩余{3,2,0}张,mex{sg[3],sg[2],sg[0]}={0,2,0},故sg[4]=1;
当n=5时,先手可以抓走5-f{1,2,4}张牌,剩余{4,3,1}张,mex{sg[4],sg[3],sg[1]}={1,0,1},故sg[5]=2;
以此类推.....
n 0 1 2 3 4 5 6 7 8 9....
sg[n] 0 1 2 0 1 2 0 1 2 0....
由上述实例我们就可以得到1~n的SG值的计算步骤,如下所示:
①、使用f数组保存可抓取的扑克牌张数。
②、然后使用vis数组来标记当前状态n的后继m状态。
③、最后模拟mex运算,也就是我们在集合mex中查找未被标记值的最小值,将其赋值给sg(n)。
④、不断的重复 ② - ③ 的步骤,即可完成计算1~n的SG值。
关于3种SG值计算方法(重点):
1、可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);
2、可选步数为任意步,SG(x) = x;
3、可选步数为一系列不连续的数,用get_SG()计算
此题就是选取第3种方法来计算SG值。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1010; 4 int n,f[11],sg[maxn]; 5 bool vis[maxn]; 6 //f[]:每次抓牌的个数 7 //sg[]: 0~n的SG函数值 8 //vis[]:mex{} 9 void init(){//初始化 10 f[1] = 1;//下标从1开始 11 for(int i=2;i<=10;++i)f[i]=f[i-1]*2;//这里只需枚举到512即可,因为1024已经超过n=1000了 12 } 13 void get_SG(){ 14 memset(sg,0,sizeof(sg)); 15 for(int i=1;i<maxn;++i){ 16 memset(vis,false,sizeof(vis));//每轮到当前i就重新初始化vis都为未访问状态,找出不属于这个集合的最小非负整数 17 for(int j=1;j<11 && f[j]<=i;++j)//j<11要放在判断条件的前面,不然会出现错误即越界,因为数组长度只有10 18 vis[sg[i-f[j]]]=true;//i-f[j]为后继状态,vis[sg[i-f[j]]]收录mex集合 19 for(int j=0;j<maxn;++j)//求没有出现在mex集合中的非负最小值 20 if(!vis[j]){sg[i]=j;break;} 21 } 22 } 23 int main() 24 { 25 init(); 26 get_SG(); 27 while(cin>>n){ 28 if(sg[n])cout<<"Kiki"<<endl;//当sg[n]不为0时,即为N-position,此时先手必赢 29 else cout<<"Cici"<<endl; 30 } 31 return 0; 32 }
题解报告:hdu 1847 Good Luck in CET-4 Everybody!(入门SG值)
标签:英语四级 判断 问题 ons eve 计算 ace bool 初始化
原文地址:https://www.cnblogs.com/acgoto/p/9095533.html