sg函数的一些题
来源:互联网 发布:怎样成为网络歌手软件 编辑:程序博客网 时间:2024/06/06 02:52
模板1如下(SG打表):
//f[]:可以取走的石子个数 //sg[]:0~n的SG函数值 //hash[]:mex{} int f[K],sg[N],hash[N]; void getSG(int n) { memset(sg,0,sizeof(sg)); for(int i=1; i<=n; i++) { memset(hash,0,sizeof(hash)); for(int j=0; f[j]<=i && j < k; j++) //k是f[]的有效长度 hash[sg[i-f[j]]]=1; for(int j=0; ; j++) { //求mes{}中未出现的最小的非负整数 if(hash[j]==0) { sg[i]=j; break; } } } }
模板2如下(dfs):
//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍 //n是集合s的大小 S[i]是定义的特殊取法规则的数组 int s[N],sg[N],n; int getSG(int x) { if(sg[x]!=-1) return sg[x]; bool vis[M]; memset(vis,0,sizeof(vis)); for(int i=0; i<n; i++) { if(x>=s[i]) vis[getSG(x-s[i])]=1; } for(i=0;; i++) if(!vis[i]) { sg[x]=i; break; } return sg[x]; }
例一: hdu 1536 S-Nim
题意:首先输入K 表示一个集合的大小 之后输入集合 表示对于这对石子只能去这个集合中的元素的个数
之后输入 一个m 表示接下来对于这个集合要进行m次询问
之后m行 每行输入一个n 表示有n个堆 每堆有n1个石子 问这一行所表示的状态是赢还是输 如果赢输入W否则L
思路:对于n堆石子 可以分成n个游戏 之后把n个游戏合起来就好了
代码:
#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long LL;const int MAXN = 108;int a[MAXN*MAXN], pre[MAXN], k;void init() { int f[MAXN]; for(int i = 1; i <= 10000; i++) { a[i] = 0; memset(f, 0, sizeof(f)); for(int j = 1; j <= k && pre[j] <= i; j++) f[a[i-pre[j]]] = 1; for(int j = 0; ; j++) if (!f[j]) { a[i] = j; break; } }}int main() { int m; //freopen("in.txt", "r", stdin); while (scanf("%d", &k) && k) { for(int i = 1; i <= k; i++) scanf("%d", pre+i); sort(pre+1, pre+k+1); init(); scanf("%d", &m); while (m--) { int n; scanf("%d", &n); int res = 0; for(int i = 1; i <= n; i++) { int t; scanf("%d", &t); res ^= a[t]; } if (res) printf("W"); else printf("L"); } puts(""); } return 0;}
例二:Gym - 101128GGame of Cards
题意:有n堆扑克牌,两个人轮流玩游戏,游戏规则:
先选一堆扑克牌,然后拿走堆顶0-k张,剩余的堆顶那一张牌上是几就必须再拿走几张,当某一方无牌可拿或者剩余张数不够必须拿走的张数时则该方输
代码:
#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long LL;const int MAXN = 1008;int a[MAXN], k, val[MAXN];void init() { int f[22]; for(int i = 1; i <= 1000; i++) { a[i] = 0; memset(f, 0, sizeof(f)); for(int j = 0; j <= k; j++) if (i-j-val[i-j] >= 0)//这里注意一下就好了; f[a[i-j-val[i-j]]] = 1; for(int j = 0; ; j++) if (!f[j]) { a[i] = j; break; } }}int main() { int m; //freopen("in.txt", "r", stdin); scanf("%d%d", &m, &k); val[0] = 1; int res = 0; while (m--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", val+i); init(); res ^= a[n]; } if (res) printf("Alice can win.\n"); else printf("Bob will win.\n"); return 0;}
sg函数巧用
hdu 1729 Stone Game
1、设当前的箱子容量为si,求出一个t满足:t + t * t < si,如果当前箱子里有ci颗石头,
1、ci > t 则必胜;
2、ci == t 则必败;
3、ci < t不能确定,将t作为si递归调用函数。
当满足ci > t时,return si - ci 作为当前状态的sg值。因为:
如图:
当ci在si点时,为有向图的端点,出度为0,也就是必败点,所以sg值为0;
当ci 位于si - 1时,ci的端点可能的sg值构成的集合为{0},所以当前sg值 为1;
当ci 位于si - 2 时,ci的端点可能的sg值构成的集合为{0, 1},所以当前的sg值为2;
。
。
。
可得,ci所在位置的sg值为si - ci;
代码:
//#include<bits/stdc++.h>#include <iostream>#include <string>#include <queue>#include <map>#include <cstring>#include <cstdio>#include <cmath>using namespace std;typedef long long LL;const int MAXN = 1000008;int sg(int c, int s) { int q = sqrt(s); while (q*(q+1) >= s) q--; if (c > q) return s-c; else return sg(c, q);//和暴力不一样有点小灵活}int main() { int n, p = 1; while (scanf("%d", &n) && n) { printf("Case %d:\n", p++); int res = 0; while (n--) { int s, c; scanf("%d%d", &s, &c); res ^= sg(c, s); } if (res) puts("Yes"); else puts("No"); } return 0;}
sg 水水的;
hdu 1730 Northcott Game
要理解sg函数啊
代码:
//#include<bits/stdc++.h>#include <iostream>#include <string>#include <queue>#include <map>#include <cstring>#include <cstdio>#include <cmath>using namespace std;typedef long long LL;const int MAXN = 1000008;int main() { int n, m; while (~scanf("%d%d", &n, &m)) { int res = 0; while (n--) { int s, c; scanf("%d%d", &s, &c); res ^= int(abs(s-c)-1); } if (res) puts("I WIN!"); else puts("BAD LUCK!"); } return 0;}
hdu 2524 A Chess Game
题意:给一些点和有向边,组成一个有向无环图(不止一个头结点,因为这个wa一次.....);在一些点上放一些棋子,2个人进行游戏,每次进行的操作是根据有向边来移动一个棋子;直到没有棋子移动,那个人就输了;
题解:明显的sg函数
代码:
//#include<bits/stdc++.h>#include <iostream>#include <string>#include <queue>#include <map>#include <cstring>#include <cstdio>#include <cmath>#include <vector>using namespace std;typedef long long LL;const int MAXN = 1008;int sg[MAXN], adjList[MAXN][MAXN], adjN[MAXN];int n;int dfs(int k) { int num[MAXN] = {0}; if (sg[k]) return sg[k]; for(int i = 0; i < adjN[k]; i++) { num[dfs(adjList[k][i])] = 1; } for(int i = 0; ; i++) if (!num[i]) return sg[k] = i;}int main() { //freopen("in.txt", "r", stdin); while (~scanf("%d", &n)) { memset(sg, 0, sizeof(sg)); for(int i = 0; i < n; i++) { scanf("%d", adjN+i); for(int j = 0; j < adjN[i]; j++) { scanf("%d", &adjList[i][j]); } } for(int i = 0; i < n; i++) dfs(i); int m; while(scanf("%d", &m) && m) { int res = 0; while(m--) { int t; scanf("%d", &t); res ^= sg[t]; } if (res) puts("WIN"); else puts("LOSE"); } } return 0;}
- sg函数的一些题
- 关于SG函数的一些演算
- [博弈]SG函数的求法和一些结论 NIM博弈
- sg函数入门题
- 对于SG函数的理解
- SG函数的基本理解
- SG函数的详细解释
- 博弈论SG函数的笔记
- poj2960 SG函数 dfs(了解sg函数的求法)
- hdu 1536 SG函数模板题 千万注意游戏的组合用SG函数值异或 是SG函数的值啊
- POJ2960(SG函数,模板题)
- sg函数
- SG函数
- SG函数
- SG函数
- SG函数
- SG函数
- SG函数
- Python中的运算符
- ubuntu使用watch命令实时监测显卡
- js事件委托
- 15.activiti工作流-工作流定义的角色组(了解)
- 【ESP8266】在ESP8266上使用JavaScript语言开发
- sg函数的一些题
- [leetcode]99. Recover Binary Search Tree
- java 集合中将元素倒序排列
- 判断浏览器类别
- 2017年上海金马五校程序设计竞赛:Problem B : Sailing
- 自定义AccessDeniedHandler
- chrome开发快捷键
- 设计模式->行为型模式->策略模式
- JavaScript 之仿flash播放器