HDU1848-Fibonacci again and again
题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=1848
这个题目代码不是很复杂,但那个等价类,(SG函数)没怎么理解,
题目难,不过代码不怎么复杂,在网上找了一些解释,
博弈题,一开始好难理解。还是用到了那个定理
对于nim游戏的某个位置(x1,x2,x3),当且仅当它各部分的nim-sum等于0时(即x1⊕x2⊕x3=0),则当前位于必败点
当时我在网络上找教程,介绍了好多,我也花了很长时间才懂的,待会我会给那个大牛的解题报告的链接,这里我就说说我的理解
这道题用到了上面那个定理,有3堆,每次只能从每堆那里移除斐波那契数的石子。由于每堆有不同的取法,所以把可能出现同种情况的数字归为一类。称为等价类。每一个类又对应一个数叫做等价类数
等价类数的算法(0其实就是必败的点,对于一堆来说)
E[0]=0;
等价类数 E[i] 的算法:
从i个中取走 fib[1],fib[2],...,fib[j]<=i 个后剩下i-fib[1], i-fib[2],..., i-fib[j]个
他们的等价类数中没有出现的最小数就是i的等价类数
例如 i=1,
取走fib[1]=1个 i-fib[1]=0,0的等价类数是0,没有出现的最小数就是1
E[1]=1;
例如 i=2,
取走fib[1]=1个 i-fib[1]=1,取走fib[2]=2个 i-fib[1]=0,
1和0的等价类数是1,0,没有出现的最小数就是2
E[2]=2;
例如 i=3
取走fib[1]=1个 i-fib[1]=2,取走fib[2]=2个 i-fib[1]=1,取走fib[3]=3个 i-fib[1]=0,
2,1和0的等价类数是2,1,0,没有出现的最小数就是3
E[3]=3;
例如 i=4
取走fib[1,2,3]=1,2,3个 剩下3,2,1,没有出现的最小数就是0
E[4]=0; 4是必败点
例如 i=5
取走fib[1,2,3,4]=1,2,3,5个 剩下4,3,2,0,等价类数是 0,3,2,0没有出现的最小数就是1
E[5]=1;
这样就得到了一个等价类数数组。接着就运用那个定理,如果一开始就出现必败点,即(e[n] ^ e[m] ^ e[p]) == 0。那么按照最优走法则必输。其它情况必赢。
详细可看详解。
http://hi.baidu.com/king___haha/blog/item/9addc65ae96948272934f029.html
代码(code)
#include<stdio.h>
#include<string.h>
int main(void)
{
int i,j,k,n,m,p;
int a[1005],b[20],c[16];//才数组为什么只要开到16呢?
b[1]=1; b[2]=2;
for(i=3;i<=16;i++)
b[i]=b[i-1]+b[i-2];
a[0]=0; a[1]=1;
for(i=2;i<=1000;i++)
{
a[i]=i;
memset(c,0,sizeof(c));
for(j=1;b[j]<=i;j++)
{
c[a[i-b[j]]]=1;
}
for(j=0;j<=15;j++)//为什么只要15看可以了呢?
{
if(c[j]==0)
{
a[i]=j;
break;
}
}
}
while(scanf("%d%d%d",&n,&m,&p)==3&&(n+m+p))
{
if(a[n]^a[m]^a[p])
printf("Fibo\n");
else
printf("Nacci\n");
}
return 0;
}
hdu1848 Fibonacci again and again 3堆
解题报告
fib[1..]={1,2,3,5,8,13,21,...};是菲波那契数列,fib[]<=1000
每次只能取 fib[i]个
1. 如果只有1堆m个,m是某个fib[i],m是必胜点,m=1,2,3,5,8,13,21,...是必胜点
易知0,4 是必败点.如果从m个中取走 k个(k=fib[i]) ,m-k是必败点
则 m是必胜点.
6-2=7-3=9-5=4是必败点, 6,7,9 是 必胜点
m=10,m-1=9,m-2=8,m-3=7,m-5=5,m-8=2
从m=10中所有取法后都是必胜点 ==> m=10是必败点
这样当只有1堆时我们可以求所有必败点,用 w[1001]表示,w[i]=0表示i是必败点
w[i]=1表示i是必胜点,
w[0]=0;w[1]=w[2]=w[3]=1;
for(i=4;i<=1000;i++)
{
for(j=1;fib[j]<=i;j++) if(w[i-fib[j]==0){w[i]=1;break;}
//取所有的Fibonacci数都胜,则该点必败
if(fib[j]>i)w[i]=0;
}
只有1堆时所有必败点:
0 4 10 14 20 24 30 36 40 46 50 56 60 66 72 76 82 86 92 96 102 108 112 118 122 128
132 138 150 160 169 176 186 192 196 202 206 212 218 222 228 232 238 242 248 254
260 264 270 274 280 284 290 296 300 306 310 316 322 326 332 338 342 348 352 358
364 368 374 378 384 388 394 400 406 410 416 420 426 430 436 442 446 452 456 462
468 472 478 484 488 494 498 504 510 514 520 524 530 534 540 552 556 562 566 572
576 582 588 592 598 602 608 618 635 644 662 672 688 694 698 704 708 714 723 730
734 740 750 754 766 772 776 782 791 798 808 814 818 824 830 834 840 844 850 854
860 866 872 876 882 886 892 896 902 908 912 918 922 928 934 938 944 950 954 960
964 970 976 980 986 990 996 1000
2. 有2堆m个和 n个
如果 m和 n都是 (1堆的)必败点,则2堆 (m,n) 也是必败点
一般 有 必败+必败=必败, 这里+不是把2队合为1堆
必败+必胜=必胜
必胜+必胜=?不一定
例如 2堆 (4,10) 是必败
(4, 5) 是必胜
易知 ( m,m )必败
定义: 如果 (m,n) 必败,则称 m和n等价
等价是相等的推广:m=n, m和n等价
只有1堆时所有必败点都和0等价,我们说只有1堆时所有必败点是第0类的或他的等价类数是0;
2堆 (1,5) 是必败的,5和1等价,和1等价的m叫做他的等价类数是1
2堆时的情况用 w2[m1][m2] 表示,w2[m1][m2]=0表示 (m1,m2)必败,
w2[m1][m2]=1表示 (m1,m2)必胜
用前面方法可算出等价类数是1的数,例如 1,5,11的等价类数是1
可以进行等价代换例如 3堆 1,5,7 可代换为 1,1,7,是必胜的
3. 结论(不证明了) 如果算出 m,n,p的等价类数是,E[m],E[n],E[p]
令 s=E[m]^E[n]^E[p]
则 s=0 是必败点
等价类数的算法
E[0]=0;
等价类数 E[i] 的算法:从i个中取走 fib[1],fib[2],...,fib[j]<=i 个后剩下
i-fib[1], i-fib[2],..., i-fib[j]个
他们的等价类数中没有出现的最小数就是i的等价类数
例如 i=1,取走fib[1]=1个 i-fib[1]=0,0的等价类数是0,没有出现的最小数就是1
E[1]=1;
例如 i=2,取走fib[1]=1个 i-fib[1]=1,取走fib[2]=2个 i-fib[1]=0,
1和0的等价类数是1,0,没有出现的最小数就是2
E[2]=2;
例如 i=3,取走fib[1]=1个 i-fib[1]=2,取走fib[2]=2个 i-fib[1]=1,取走fib[3]=3个 i-fib[1]=0,
2,1和0的等价类数是2,1,0,没有出现的最小数就是3
E[3]=3;
例如 i=4,取走fib[1,2,3]=1,2,3个 剩下3,2,1,没有出现的最小数就是0
E[4]=0; 4是必败点
例如 i=5,取走fib[1,2,3,4]=1,2,3,5个 剩下4,3,2,0,等价类数是 0,3,2,0没有出现的最小数就是1
E[5]=1;
//计算等价类数
E[0]=0;E[1]=1;
for(i=2;i<=1000;i++)
{ //首先假设 i<=1000时 等价类数<=15
for(j=0;j<=15;j++)h[j]=0;// h[j]==0, j没有出现,h[j]=1,j出现
for(j=1;fib[j]<=i;j++)
{
h[ E[i-fib[j]] ]=1;
}
for(j=0;j<=15;j++)if(h[j]==0){E[i]=j;break;}//h[j]=0,j没有出现
}
因此计算步骤是:
1.计算菲波那契数列fib[i],计算到 fib[i]>1000为止
2.计算等价类数 E[i]
3. 同上面的 3
HDU1848-Fibonacci again and again的更多相关文章
- HDU1848 Fibonacci again and again SG函数
Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- hdu-------(1848)Fibonacci again and again(sg函数版的尼姆博弈)
Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- HDU1848 Fibonacci again and again(SG 函数)
任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: F(1)=1; F(2)=2; F(n)=F(n-1)+F(n-2)(n>=3); 所以,1, ...
- hdu1848 Fibonacci again and again [组合游戏]
http://acm.hdu.edu.cn/showproblem.php?pid=1848 Problem Description 任何一个大学生对菲波那契数列(Fibonacci numbers) ...
- hdu1848 Fibonacci again and again(SG游戏功能)
现在的变化是看不清楚SG功能什么寻求方法 临时模板标题是首当 性能mex1它正在寻求g(x) 然后XOR #include<cstdio> #include<iostream> ...
- HDU1848 Fibonacci again and again 博弈 SG函数
题意:三堆石子,每次能拿走斐波那契数个石子,先取完石子胜,问先手胜还是后手胜 石子个数<=1000 多组数据 题目链接:http://acm.hdu.edu.cn/showproblem.ph ...
- 【博弈论】【SG函数】hdu1848 Fibonacci again and again
某个状态的SG函数被定义为 除该状态能一步转移到的状态的SG值以外的最小非负整数. 有如下性质:从SG值为x的状态出发,可以转移到SG值为0,1,...,x-1的状态. 不论SG值增加与否,我们都可以 ...
- $HDU1848\ Fibonacci\ again\ and\ again$ 博弈论
正解:博弈论 解题报告: 传送门! 首先按照套路显然是考虑先预处理出所有数的$SG$函数值然后全局的$SG$就是$SG(n)$^$SG(m)$^$SG(p)$,这儿应该麻油问题$QwQ$? 然后就考虑 ...
- sg函数小结
sg函数小结 sg函数是处理博弈问题的重要工具. 我们知道sg(x)=mex{sg(j)|x能到达状态j} sg(x)=0时代表后手赢,否则先手赢. 对于一个问题,如果某些子问题是相互独立的,我们就可 ...
随机推荐
- Web安全检测工具的使用.
Nikto2 Nikto2是一款使用perl语言写的多平台扫描软件,是一款命令行模式的工具,它可以扫描指定主机的WEB类型 主机名.特定目录.Cookie.特定CGI漏洞.XSS漏洞.sql注入漏洞. ...
- Ubuntu下安装Hudson
因为hudson需要依赖java等,手动安装比较费劲 官方给出了一种很简单的解决方案:http://wiki.eclipse.org/Hudson-ci/Installing_Hudson_DEB 1 ...
- (转)Hadoop MapReduce链式实践--ChainReducer
版本:CDH5.0.0,HDFS:2.3.0,Mapreduce:2.3.0,Yarn:2.3.0. 场景描述:求一组数据中按照不同类别的最大值,比如,如下的数据: data1: A,10 A,11 ...
- UCI机器学习数据库
UC Irvine Machine Learning Repository:UCI指的是加州大学欧文分校.UCI机器学习库主要是收集的机器学习领域的一些相关数据集和数据生成器,可以用来做一些基本的实验 ...
- zencart 具体页面调用规则: $body_code变量解析
zencart $body_code变量解析 修改centerColumn 可以修改中间产品方框的大小 2.2.5 .BODY文件在这个文件生效 require($body_code) include ...
- implemented loader.php
http://stackoverflow.com/questions/11787176/manage-url-routes-in-own-php-framework This is how i imp ...
- redis sentinel 集群监控 配置
环境: ip 172.16.1.31 26379 redis sentinel ip 172.16.1.30 6379 主 1 ip 172.16.1.31 6380 从 1 ip ...
- OC语言的特性(一)-消息传递与调用函数的表现形式
我们在初学Objective-C时,都会觉得ObjC中的消息传递和其他语言的调用函数差不多,只是在OC中,方法调用用消息传递这一概念来代替. 那么到底怎样区别OC中的消息传递与其他语言的调用函数呢. ...
- Scala中function的理解
在函数式语言中,函数是和value一样地位的一等公民,他可以作为变量,或者作为参数传递给另一个函数 ##作为变量 val f=(x:Int)=>x+1 为啥可以这样写? 由于scala是OOP, ...
- 2.4 easyui - panel的使用
<div id="p" class="easyui-panel" title="My Panel" style ...