博弈问题方法单-----找规律篇
来源:互联网 发布:ubuntu c 开发 编辑:程序博客网 时间:2024/05/28 19:23
1、题目:
[vijos1196] 吃糖果游戏
题解:
一开始看看感觉还可以用【科学的】二维SG,一看数据,10000位,exm?
于是我先写了个SG函数,敲进去几个数据
啊我好像看到规律了!—> AC
嘛这样打表是不行的,我们还是看个正解吧
当游戏状态属于前者时,Matrix67可以把糖果数被5除余1、4或正好除尽的那一堆分成糖果数被5除余数都是2或3的两堆(他总能做到这一点)
而对方不得不把其中一堆糖果又分出新的糖果数被5除余1、4或正好除尽的一堆留给Matrix67操作。
这样逼着对方总是面临必败的状态,使得最后对方不得不把2个糖果或者3个糖果分成两堆,
从而使Matrix67赢得游戏。
反过来,当Matrix67面临两堆糖果的数目被5除余数都是2或3的状态时,Shadow总可以取胜。
所以就是如果两堆的个数的个位数都是2 3 7 8的一个的话
就是Shadow取胜,不然就是Matrix
代码:
暴力【表】
#include <cstdio>#include <cstring>#include <iostream>using namespace std;int sg[1005][1005],n,m;int get_sg(int x,int y){ if (x>y) swap(x,y); if (sg[x][y]!=-1) return sg[x][y]; if (x==1 || y==1) {sg[x][y]=1; return 1;} bool ext[1005];memset(ext,0,sizeof(ext)); for (int i=1;i+i<=y;i++) ext[get_sg(i,y-i)]=1; for (int i=1;i+i<=x;i++) ext[get_sg(i,x-i)]=1; for (int i=0;;i++) if (!ext[i]){sg[x][y]=i;break;} return sg[x][y];}int main(){ memset(sg,-1,sizeof(sg)); while (1) { scanf("%d%d",&n,&m); if (get_sg(n,m)) printf("先手\n");else printf("后手\n"); }}
AC
#include <cstdio>#include <cstring>using namespace std;char x[10005],y[10005];int main(){ for (int i=1;i<=10;i++) { scanf("%s%s",x,y); int l1=strlen(x)-1,l2=strlen(y)-1; if ((x[l1]=='2'||x[l1]=='3'||x[l1]=='7'||x[l1]=='8')&&(y[l2]=='2'||y[l2]=='3'||y[l2]=='7'||y[l2]=='8')) printf("Shadow\n");else printf("Matrix67\n"); }}
2、题目
[POJ2505] A multiplication game
题解:
首先想到打表,但这什么鬼啊我不会啊!那就硬找规律?
容易发现
[1,9]Stan
[10,18]Ollie
[19,162]Stan
…
我们可以这样极限考虑,要是Stan知道ta会赢,那每回合会选最大的9,Ollie知道自己乘上也没什么用,给ta个最小的2,然后Stan选个9就能达到自己的目标,Ollie要是赢的话是同样的 然后你随便试试19-162之间的数就发现Ollie总是不能赢,就可以发现规律了
1~9*1 Stan
9*1+1~9*2 Ollie
9*2+1~9*2*9 Stan
那么我们往下推测
9*2*9+1~9*2*9*2 Ollie
规律get?
其实还有一个问题是这个数字很大,但是可以用double读入
代码:
#include <cstdio>#include <iostream>using namespace std;double n;int main(){ while (~scanf("%lf",&n)) { while (1) { if (n<=9) {printf("Stan wins.\n");break;} if (n<=18) {printf("Ollie wins.\n");break;} n/=18; } }}
3、题目:
[HDU3032] Nim or not Nim?
题意:
Alice和Bob轮流取石子,每一次可以从任意一堆中拿走任意个石子,也可以将一堆石子分为两个小堆。先拿完者获胜。
题解:
这个问题可以用SG函数来解决。首先,操作①其实和Nim游戏没什么区别,对于一个石子数为k的点来说,后继可以为0…k-1。而操作②实际上是把一个游戏分成了两个游戏。根据游戏的和的概念,这两个游戏的和应该为两个子游戏的SG函数值的异或。
比如说,状态3的后继有:0、1、2、(1,2),他们的SG值分别为0、1、2、3,所以sg(3) = 4
但是一看数据范围2^31 - 1。。。然后打了个表,规律get?
代码:
#include <cstdio>#include <cstring>using namespace std;int sg[10005];int get_sg(int x){ if (sg[x]!=-1) return sg[x]; bool ext[10005];memset(ext,0,sizeof(ext)); for (int i=x-1;i>=0;i--) ext[get_sg(i)]=1; for (int i=1;i+i<=x;i++) ext[get_sg(i)^get_sg(x-i)]=1; for (int i=0;;i++) if (!ext[i]) {sg[x]=i; break;} return sg[x];}int find_sg(int x){ if (x%4==3) return x+1; if (x%4==0) return x-1; return x;}int main(){ //表 /* memset(sg,-1,sizeof(sg)); for (int i=1;i<=50;i++) printf("sg[%d]=%d\n",i,get_sg(i));*/ int T,n; scanf("%d",&T); while (T--) { int k=0,a; scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&a); k^=find_sg(a); } if (k) printf("Alice\n");else printf("Bob\n"); }}
4、题目:
[BZOJ2463] [中山市选2009] 谁能赢呢?
题解:
这题什么鬼啊,我为什么连暴力都不会啊?
然后画了几个格子试一试,发现早晚他们都会把整个棋盘走一遍,那不就是看这个棋盘格子的奇偶吗。。
再退一步,这不就是看行数的奇偶吗。。
AC。
代码:
#include <cstdio>using namespace std;int main(){ int n; while (scanf("%d",&n) && n) { if (n%2) printf("Bob\n"); else printf("Alice\n"); }}
- 博弈问题方法单-----找规律篇
- HDOJ1525 [找规律博弈]
- hdu1079 找规律/博弈
- 博弈问题方法单-----对称性篇
- hdu 1525找规律博弈
- hdu 1847 博弈找规律
- hdu 2147博弈找规律
- hdu 2516博弈找规律
- HDU 2147博弈-找规律
- hdu3951(博弈)找规律
- ACM-博弈之找规律
- 博弈 找规律 poj 2484
- Calendar Game(找规律+博弈)
- hdu 5708 博弈找规律
- hdu1517 找规律/乘法博弈
- 【博弈+找规律】HDU_4642_Fliping game
- 【博弈+找规律】HDU_5963_朋友
- hdoj 4203 Doubloon Game(博弈+找规律)
- vue使用nuxt实现服务器端渲染
- Testing Round #14 (Unrated) C
- 各种要有认知的常识、技巧(updating~~)
- Open GL的安装和认识
- 计算机网络原理重要概念
- 博弈问题方法单-----找规律篇
- (洛谷 1004 ssl 1010)方格取数
- 反向安装jar包到本地仓库
- 你好
- ElasticSearch 常用的结构化查询字符串(持续更新中...)
- AtCoder Beginner Contest 082
- arcgis api for js之echarts开源js库实现地图统计图分析
- Linux环境 无法通过terminal直接打开Vivado
- php算法和数据结构