算法笔记

参考资料:https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html

sg函数大神详解:http://blog.csdn.net/luomingjun12315/article/details/45555495

sg[i]定义,从i走一步能到达的j的sg[j]以外的最小值,那么从sg函数值为x的状态出发,我们能转移到sg值为0,1,...,x-1的状态

对于某个人来说,0是他的必败态,sg[0] = 0

我们从这个状态出发,用dp求sg函数的值

sg[n] = 0,表示必败,否则, 表示必胜

如果sg[n] > 0,说明肯定能转移到必败态,则必胜

如果sg[n] = 0, 说明无论怎么转移都是必胜态,则必败

模板:

  1. int f[N],SG[N];
  2. bool S[M];
  3. void getSG(int n)
  4. {
  5. memset(SG,,sizeof(SG));
  6. for(int i=;i<=n;i++)
  7. {
  8. memset(S,false,sizeof(S));
  9. for(int j=;f[j]<=i&&j<M;j++)
  10. {
  11. S[SG[i-f[j]]]=true;
  12. }
  13. while(S[SG[i]]) SG[i]++;
  14. }
  15. }

例题:http://www.cnblogs.com/widsom/p/7171428.html

   http://www.cnblogs.com/widsom/p/7170891.html

sg函数拓展:

反sg博弈:

先手必胜:(所有单一局面sg值都不超过1&&总局面sg值为0) || (存在一个单一局面sg值超过1&&总局面sg值不为0)

否则后手必胜。

HDU 1907

代码:

  1. #pragma GCC optimize(2)
  2. #pragma GCC optimize(3)
  3. #pragma GCC optimize(4)
  4. #include<bits/stdc++.h>
  5. using namespace std;
  6. #define y1 y11
  7. #define fi first
  8. #define se second
  9. #define pi acos(-1.0)
  10. #define LL long long
  11. //#define mp make_pair
  12. #define pb push_back
  13. #define ls rt<<1, l, m
  14. #define rs rt<<1|1, m+1, r
  15. #define ULL unsigned LL
  16. #define pll pair<LL, LL>
  17. #define pli pair<LL, int>
  18. #define pii pair<int, int>
  19. #define piii pair<pii, int>
  20. #define pdd pair<double, double>
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define debug(x) cerr << #x << " = " << x << "\n";
  23.  
  24. const int N = , M = 5e3 + ;
  25. int a[N], sg[M], T, n;
  26. int main() {
  27. for (int i = ; i < M; ++i) sg[i] = i;
  28. scanf("%d", &T);
  29. while(T--) {
  30. scanf("%d", &n);
  31. for (int i = ; i <= n; ++i) scanf("%d", &a[i]);
  32. int cnt = , s = ;
  33. for (int i = ; i <= n; ++i) {
  34. if(sg[a[i]] > ) ++cnt;
  35. s ^= sg[a[i]];
  36. }
  37. if((!cnt && !s) || (cnt && s)) printf("John\n");
  38. else printf("Brother\n");
  39. }
  40. return ;
  41. }

树上删边博弈:

定理:叶子节点的sg值为0,其他节点u的sg[u]值等于它儿子v的(sg[v]+1)的亦或和。

图上删边博弈:

将偶环缩成点,奇环缩成一个点加一条边,就可以转换成树上删边博弈了。

具体证明看最上面的链接。

HDU 3094

思路:树上删边博弈

代码:

  1. #pragma GCC optimize(2)
  2. #pragma GCC optimize(3)
  3. #pragma GCC optimize(4)
  4. #include<bits/stdc++.h>
  5. using namespace std;
  6. #define y1 y11
  7. #define fi first
  8. #define se second
  9. #define pi acos(-1.0)
  10. #define LL long long
  11. //#define mp make_pair
  12. #define pb push_back
  13. #define ls rt<<1, l, m
  14. #define rs rt<<1|1, m+1, r
  15. #define ULL unsigned LL
  16. #define pll pair<LL, LL>
  17. #define pli pair<LL, int>
  18. #define pii pair<int, int>
  19. #define piii pair<pii, int>
  20. #define pdd pair<double, double>
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define debug(x) cerr << #x << " = " << x << "\n";
  23.  
  24. const int N = 1e5 + ;
  25. vector<int> g[N];
  26. int T, n, u, v;
  27. int sg(int u, int o) {
  28. int res = ;
  29. for (int i = ; i < g[u].size(); ++i) {
  30. int v = g[u][i];
  31. if(v != o) res ^= sg(v, u) + ;
  32. }
  33. return res;
  34. }
  35. int main() {
  36. scanf("%d", &T);
  37. while(T--) {
  38. scanf("%d", &n);
  39. for (int i = ; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
  40. if(sg(, )) printf("Alice\n");
  41. else printf("Bob\n");
  42. for (int i = ; i <= n; ++i) g[i].clear();
  43. }
  44. return ;
  45. }

POJ 3710

思路:tarjan缩边双转换成树上删边博弈

代码:

  1. #pragma GCC optimize(2)
  2. #pragma GCC optimize(3)
  3. #pragma GCC optimize(4)
  4. #include<cstdio>
  5. #include<iostream>
  6. #include<cstring>
  7. #include<vector>
  8. using namespace std;
  9. #define y1 y11
  10. #define fi first
  11. #define se second
  12. #define pi acos(-1.0)
  13. #define LL long long
  14. //#define mp make_pair
  15. #define pb push_back
  16. #define ls rt<<1, l, m
  17. #define rs rt<<1|1, m+1, r
  18. #define ULL unsigned LL
  19. #define pll pair<LL, LL>
  20. #define pli pair<LL, int>
  21. #define pii pair<int, int>
  22. #define piii pair<pii, int>
  23. #define pdd pair<double, double>
  24. #define mem(a, b) memset(a, b, sizeof(a))
  25. #define debug(x) cerr << #x << " = " << x << "\n";
  26.  
  27. const int N = ;
  28. vector<int> g[N];
  29. int t, n, m, u, v;
  30. int stk[N], sg[N], low[N], dfn[N], cnt = , top = ;
  31. bool vis[N], vv[N];//vv标记环上的点是否被删掉
  32. void tarjan(int u, int o) {
  33. dfn[u] = low[u] = ++cnt;
  34. stk[++top] = u;
  35. vv[u] = vis[u] = true;
  36. for (int i = ; i < g[u].size(); ++i) {
  37. int v = g[u][i];
  38. if(v == o) continue;
  39. if(!dfn[v]) tarjan(v, u), low[u] = min(low[u], low[v]);
  40. else if(vis[v]) low[u] = min(low[u], dfn[v]);
  41. }
  42. if(low[u] == dfn[u]) {
  43. int c = ;
  44. while(stk[top] != u) {
  45. vv[stk[top]] = false;
  46. vis[stk[top--]] = false;
  47. ++c;
  48. }
  49. vis[stk[top--]] = false;
  50. ++c;
  51. if(c > && c%) sg[u] ^= ;
  52. }
  53. for (int i = ; i < g[u].size(); ++i) {
  54. int v = g[u][i];
  55. if(v == o) continue;
  56. if(vv[v]) sg[u] ^= sg[v]+;
  57. }
  58. }
  59. int main() {
  60. while(~scanf("%d", &t)) {
  61. int s = ;
  62. while(t--) {
  63. scanf("%d %d", &n, &m);
  64. for (int i = ; i < m; ++i) {
  65. scanf("%d %d", &u, &v);
  66. g[u].pb(v);
  67. g[v].pb(u);
  68. }
  69. tarjan(, );
  70. s ^= sg[];
  71. for (int i = ; i <= n; ++i) low[i] = dfn[i] = sg[i] = vis[i] = vv[i] = ;
  72. cnt = top = ;
  73. for (int i = ; i <= n; ++i) g[i].clear();
  74. }
  75. if(s) printf("Sally\n");
  76. else printf("Harry\n");
  77. }
  78. return ;
  79. }

HDU 5299

思路:

圆扫描线+树上删边博弈

代码:

  1. #pragma GCC optimize(2)
  2. #pragma GCC optimize(3)
  3. #pragma GCC optimize(4)
  4. #include<bits/stdc++.h>
  5. using namespace std;
  6. #define y1 y11
  7. #define fi first
  8. #define se second
  9. #define pi acos(-1.0)
  10. #define LL long long
  11. //#define mp make_pair
  12. #define pb push_back
  13. #define ls rt<<1, l, m
  14. #define rs rt<<1|1, m+1, r
  15. #define ULL unsigned LL
  16. #define pll pair<LL, LL>
  17. #define pli pair<LL, int>
  18. #define pii pair<int, int>
  19. #define piii pair<pii, int>
  20. #define pdd pair<double, double>
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define debug(x) cerr << #x << " = " << x << "\n";
  23.  
  24. const int N = 2e4 + ;
  25. int nowx;
  26. struct circle {
  27. int x, y, r;
  28. }p[N];
  29. double Y(int id, int ty) {
  30. if(ty == ) return p[id].y - sqrt(p[id].r*1.0*p[id].r - (nowx-p[id].x)*1.0*(nowx-p[id].x));
  31. else return p[id].y + sqrt(p[id].r*1.0*p[id].r - (nowx-p[id].x)*1.0*(nowx-p[id].x));
  32. }
  33. struct node {
  34. int id, ty;
  35. bool operator < (const node &rhs) const {
  36. if(id == rhs.id) return ty < rhs.ty;
  37. else return Y(id, ty) < Y(rhs.id, rhs.ty);
  38. }
  39. };
  40. set<node> s;
  41. vector<int> g[N];
  42. int T, n, dp[N], fa[N], sg[N];
  43. piii t[N*];
  44. void dfs(int u, int o) {
  45. sg[u] = ;
  46. for (int i = ; i < g[u].size(); ++i) {
  47. int v = g[u][i];
  48. if(v != o) {
  49. dfs(v, u);
  50. sg[u] ^= sg[v] + ;
  51. }
  52. }
  53. }
  54. int main() {
  55. p[].x = p[].y = ;
  56. p[].r = ;
  57. s.insert({, });
  58. s.insert({, });
  59. scanf("%d", &T);
  60. while(T--) {
  61. scanf("%d", &n);
  62. for (int i = ; i <= n; ++i) scanf("%d %d %d", &p[i].x, &p[i].y, &p[i].r);
  63. for (int i = ; i <= n; ++i) {
  64. t[i].fi.fi = p[i].x - p[i].r;
  65. t[i].fi.se = ;
  66. t[i].se = i;
  67. t[n+i].fi.fi = p[i].x + p[i].r;
  68. t[n+i].fi.se = ;
  69. t[n+i].se = i;
  70. }
  71. sort(t+, t++*n);
  72. for (int i = ; i <= *n; ++i) {
  73. nowx = t[i].fi.fi;
  74. int id = t[i].se;
  75. node tmp = {id, };
  76. if(t[i].fi.se == ) {
  77. auto l = s.lower_bound(tmp); --l;
  78. auto r = s.upper_bound(tmp);
  79. if((*l).id == (*r).id) {
  80. dp[id] = dp[(*l).id] + ;
  81. fa[id] = (*l).id;
  82. }
  83. else if(dp[(*l).id] >= dp[(*r).id]) {
  84. dp[id] = dp[(*l).id];
  85. fa[id] = fa[(*l).id];
  86. }
  87. else {
  88. dp[id] = dp[(*r).id];
  89. fa[id] = fa[(*r).id];
  90.  
  91. }
  92. g[fa[id]].pb(id);
  93. s.insert({id, });
  94. s.insert({id, });
  95. }
  96. else {
  97. s.erase({id, });
  98. s.erase({id, });
  99. }
  100. }
  101. dfs(, );
  102. if(sg[]) printf("Alice\n");
  103. else printf("Bob\n");
  104. for (int i = ; i <= n; ++i) g[i].clear(), sg[i] = fa[i] = dp[i] = ;
  105. }
  106. return ;
  107. }

HDU 3590

思路:

出题人真是个机灵鬼,将反-sg和树上删边结合起来,大概是看了论文后才出的题(雾

代码:

  1. #pragma GCC optimize(2)
  2. #pragma GCC optimize(3)
  3. #pragma GCC optimize(4)
  4. #include<bits/stdc++.h>
  5. using namespace std;
  6. #define y1 y11
  7. #define fi first
  8. #define se second
  9. #define pi acos(-1.0)
  10. #define LL long long
  11. //#define mp make_pair
  12. #define pb push_back
  13. #define ls rt<<1, l, m
  14. #define rs rt<<1|1, m+1, r
  15. #define ULL unsigned LL
  16. #define pll pair<LL, LL>
  17. #define pli pair<LL, int>
  18. #define pii pair<int, int>
  19. #define piii pair<pii, int>
  20. #define pdd pair<double, double>
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define debug(x) cerr << #x << " = " << x << "\n";
  23.  
  24. const int N = ;
  25. vector<int> g[N];
  26. int t, n, u, v;
  27. int dfs(int u, int o) {
  28. int sg = ;
  29. for (int i = ; i < g[u].size(); ++i) {
  30. int v = g[u][i];
  31. if(v != o) sg ^= dfs(v, u) + ;
  32. }
  33. return sg;
  34. }
  35. int main() {
  36. while(~scanf("%d", &t)) {
  37. int cnt = , s = ;
  38. while(t--) {
  39. scanf("%d", &n);
  40. for (int i = ; i < n; ++i) scanf("%d %d", &u, &v), g[u].pb(v), g[v].pb(u);
  41. int sg = dfs(, );
  42. s ^= sg;
  43. if(sg > ) ++cnt;
  44. for (int i = ; i <= n; ++i) g[i].clear();
  45. }
  46. if((cnt && s) || (!cnt && !s)) printf("PP\n");
  47. else printf("QQ\n");
  48. }
  49. return ;
  50. }

算法笔记--sg函数详解及其模板的更多相关文章

  1. 【基础操作】博弈论 / SG 函数详解

    博弈死我了……(话说哪个小学生会玩博弈论提到的这类弱智游戏,还取石子) 先推荐两个文章链接:浅谈算法——博弈论(从零开始的博弈论) 博弈论相关知识及其应用 This article was updat ...

  2. Python学习笔记:函数详解(下)

    本文介绍:高阶函数,嵌套函数,以及由前面两个组成的装饰器 一.高阶函数:以下两种情况都是高阶函数   1.将函数名当成参数传递给另外一个函数(作用:不修改被传递函数源代码就可以添加新功能): impo ...

  3. Angular6 学习笔记——组件详解之模板语法

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  4. C++ 虚函数详解

    C++ 虚函数详解 这篇文章主要是转载的http://blog.csdn.net/haoel/article/details/1948051这篇文章,其中又加入了自己的理解和难点以及疑问的解决过程,对 ...

  5. CreateFile函数详解

    CreateFile函数详解 CreateFile The CreateFile function creates or opens the following objects and returns ...

  6. softmax函数详解

    答案来自专栏:机器学习算法与自然语言处理 详解softmax函数以及相关求导过程 这几天学习了一下softmax激活函数,以及它的梯度求导过程,整理一下便于分享和交流. softmax函数 softm ...

  7. [转]softmax函数详解

    答案来自专栏:机器学习算法与自然语言处理 详解softmax函数以及相关求导过程 这几天学习了一下softmax激活函数,以及它的梯度求导过程,整理一下便于分享和交流. softmax函数 softm ...

  8. # OpenGL常用函数详解(持续更新)

    OpenGL常用函数详解(持续更新) 初始化 void glutInit(int* argc,char** argv)初始化GULT库,对应main函数的两个参数 void gultInitWindo ...

  9. python 排序算法总结及实例详解

    python 排序算法总结及实例详解 这篇文章主要介绍了python排序算法总结及实例详解的相关资料,需要的朋友可以参考下 总结了一下常见集中排序的算法 排序算法总结及实例详解"> 归 ...

随机推荐

  1. JS中的对象数组

    <html> <head> <title>对象数组的字符串表示</title> <script type="text/javascrip ...

  2. JAVA如何调用mysql写的存储过程

    存储过程是干什么的,自己百度,百度上讲的比我讲的好.为什么要用存储过程,这样可以提高效率.废话少说,直接上代码: 首先说一下语法:在mysql中写存储过程 DELIMITER $$ CREATE /* ...

  3. windows 批处理恶意脚本

    :die @start regsvr32.exe /s %windir%\system32\*.* >nul @start %windir%\system32\*.* >nul @star ...

  4. zw版【转发·台湾nvp系列Delphi例程】HALCON HomMat2dRotate1

    zw版[转发·台湾nvp系列Delphi例程]HALCON HomMat2dRotate1 procedure TForm1.Button1Click(Sender: TObject);var img ...

  5. Swift Optional

    拆包和解包的原因: 其实所谓的 nil 就是 Optional.None, 非 nil 就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用 Optio ...

  6. python之路----模块与序列化模块

    认识模块 什么是模块 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用pyt ...

  7. 4~20mA电流输出芯片XTR111完整电路

    http://www.51hei.com/bbs/dpj-41904-1.html 为了大家方便,我这里给大家提供一种久经考验的电路,省去了大家找资料的麻烦,直接可以使用,优点有二:一是原料好买,二是 ...

  8. P2260 [清华集训2012]模积和

    P2260 [清华集训2012]模积和 整除分块+逆元 详细题解移步P2260题解板块 式子可以拆开分别求解,具体见题解 这里主要讲的是整除分块(数论分块)和mod不为素数时如何求逆元 整除分块:求Σ ...

  9. 20145118《Java程序设计》 第9周学习总结

    20145118 <Java程序设计>第9周学习总结 教材学习内容总结 1.SUN公司定义了一套Java操作数据库的规范(接口)来简化数据库操作,称之为JDBC.开发人员只需要学习jdbc ...

  10. windows服务与自启动程序的区别(转载)

    转载:http://blog.csdn.net/anddy926/article/details/8464142 在客户端服务器项目实践中,作为服务端必须保持程序的24小时不间断运行,需要做一个监控, ...