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时代表后手赢,否则先手赢. 对于一个问题,如果某些子问题是相互独立的,我们就可 ...
随机推荐
- IE6下绝对定位元素父级宽高是奇数,绝对定位元素的right和bottom值会有1个像素的偏差
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Python3基础 函数名.__doc__显示一个函数的单行与多行函数文档
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- 2016"百度之星" - 资格赛(Astar Round1) Problem A
保存前缀乘,询问的时候输出c[ri]/c[li-1]即可,因为是除法,所以计算一下c[li-1]的逆元. #include <stdio.h> #include <math.h> ...
- Gradle依赖项学习总结,dependencies、transitive、force、exclude的使用与依赖冲突解决
http://www.paincker.com/gradle-dependencies https://docs.gradle.org/current/userguide/dependency_man ...
- 微信小程序实例教程(四)
第八章:微信小程序分组开发与左滑功能实现 先来看看今天的整体思路: 进入分组管理页面 --> 点击新建分组新建 进入到未分组页面基本操作 进入到已建分组里面底部菜单栏操作 --> 从名 ...
- Visual C++ 6.0 解决win 8.1不兼容的问题。--技术宅从来不妥协
因为目标院校复试上机需要使用这一个软件,所以在成功的路上的遇到的问题记录,避免二次犯错,在网站上下载并且安装Visual C++ 6.0,运行时会提示不兼容的问题,怎么办呢?当然不是下载他们所推荐的V ...
- C语言实现GBK/GB2312/五大码之间的转换(转)
源:C语言实现GBK/GB2312/五大码之间的转换 //----------------------------------------------------------------------- ...
- Apache处理请求步骤及过程
Apache请求处理循环详解 : 1.Post-Read-Request阶段: 在正常请求处理流程中,这是模块可以插入钩子的第一个阶段.对于那些想很早进入处理请求的模块来说,这个阶段可以被利用. 2. ...
- Qt下libusb-win32的使用方法(转)
源:Qt下libusb-win32的使用方法 之前一直找不到适合WIN7下的Tiny6410的USB下载软件,正好这几天开始学习USB,所以打算自己写一个专门用于Tiny6410的WIN7下的USB下 ...
- OpenGL ES
前言 OpenGL ES是Khronos Group创建的一系列API中的一种(官方组织是:http://www.khronos.org/).在桌面计算机上有两套标准的 3DAPI:Direct3D和 ...