博弈题目小结

HDU 2174 kiki‘s game

题意:有一个N*M的棋盘,起点在右上角,两个人每轮可把棋子向左、向下或者向左下移动一格,直到不能移动棋子者输。

NP图解决:

概念:

必败点(P点):前一个选手将取胜的位置称为必败点。

必胜点(N点):下一个选手将取胜的位置成为必胜点。

性质:

步骤:

NP图:

AC code:

 1 #include <bits/stdc++.h>
 2 #define inc(i, j, k) for(int i = j; i <= k; i++)
 3 #define rep(i, j, k) for(int i = j; i < k; i++)
 4 #define F(x) ((x)/3+((x)%3==1?0:tb))
 5 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 #define MEM(i, j) memset(i, j, sizeof(i));
 9 #define gcd(i, j) __gcd(i, j)
10 using namespace std;
11
12 int main()
13 {
14     int a, b;
15     while(~scanf("%d %d", &a, &b)){
16         if(a == 0 && b == 0) break;
17         if(a%2 == 1 && b%2 == 1) puts("What a pity!");
18         else puts("Wonderful!");
19     }
20     return 0;
21 }

HDU 2149  Public Sale

题意:

底价为 0,最低成交价为 M,两位博弈,每轮叫价区间 1~N

求 先手开始有多少种取胜叫价,输出每种叫价值。

解题思路:

巴什博弈变形,只要能把 (N+1) * t 留给对手必胜,如果自己是(N+1)*r 必败。

AC code:

 1 #include <bits/stdc++.h>
 2 #define inc(i, j, k) for(int i = j; i <= k; i++)
 3 #define rep(i, j, k) for(int i = j; i < k; i++)
 4 #define F(x) ((x)/3+((x)%3==1?0:tb))
 5 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 #define MEM(i, j) memset(i, j, sizeof(i));
 9 #define gcd(i, j) __gcd(i, j)
10 using namespace std;
11
12 int main()
13 {
14     int N, M;
15     while(~scanf("%d %d", &M, &N)){
16         if(M <= N){
17             for(int i = M; i <= N; i++){
18                 printf("%d%c", i, i==N?‘\n‘:‘ ‘);
19             }
20         }
21         else if(M%(N+1) == 0) puts("none");
22         else{
23             printf("%d\n", M%(N+1));
24         }
25     }
26     return 0;
27 }

HDU 1907 John

题意:

有 N 堆物品,每轮选着一堆拿走若干物品,拿走最后一个物品的输;

解题思路:

Nim博弈变形,异或判断是否为奇异局势, 面对奇异局势先手必败,如果全是 1 判断奇偶性,偶数则先手胜。

AC code:

 1 #include <bits/stdc++.h>
 2 #define inc(i, j, k) for(int i = j; i <= k; i++)
 3 #define rep(i, j, k) for(int i = j; i < k; i++)
 4 #define F(x) ((x)/3+((x)%3==1?0:tb))
 5 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 #define MEM(i, j) memset(i, j, sizeof(i));
 9 #define gcd(i, j) __gcd(i, j)
10 using namespace std;
11 char ans1[] = "John", ans2[] = "Brother";
12 int main()
13 {
14     int N, sum;
15     bool flag = false;
16     int T_case, tp;
17     scanf("%d", &T_case);
18     while(T_case--){
19         flag = false;
20         scanf("%d", &N);scanf("%d", &sum);
21         if(sum > 1) flag = true;
22         inc(i, 2, N){
23             scanf("%d", &tp);
24             if(tp > 1) flag = true;
25             sum^=tp;
26         }
27         if(!flag) printf("%s", N%2?ans2:ans1);
28         else printf("%s", sum==0?ans2:ans1);
29         puts("");
30     }
31     return 0;
32 }

HDU 2509 Be the Winner

题意:同上;

解题思路:同上;

HDU 1850 Being a Good Boy in Spring Festival

题意:有 N 堆 扑克牌,每轮选择其中一堆拿走任意张牌,拿走最后一张牌的胜,问先手如果想取胜,第一步有多少种选择?

解题思路:

Nim博弈变形;

原理、方法都很详细:https://www.cnblogs.com/kuangbin/archive/2011/11/24/2262389.html

即枚举每一堆是否可以删掉一些值变成奇异局势。

AC code:

 1 #include <bits/stdc++.h>
 2 #define inc(i, j, k) for(int i = j; i <= k; i++)
 3 #define rep(i, j, k) for(int i = j; i < k; i++)
 4 #define F(x) ((x)/3+((x)%3==1?0:tb))
 5 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 #define MEM(i, j) memset(i, j, sizeof(i));
 9 #define gcd(i, j) __gcd(i, j)
10 using namespace std;
11 const int MAXN = 2e5+10;
12 int tp[MAXN];
13 int main()
14 {
15     int N, sum = 0;
16     while(~scanf("%d", &N) && N){
17         int ans = 0;
18         scanf("%d", &sum);
19         tp[1] = sum;
20         inc(i, 2, N){
21             scanf("%d", &tp[i]);
22             sum^=tp[i];
23         }
24         inc(i, 1, N){
25             if(tp[i] > (sum^tp[i])) ans++;
26         }
27         printf("%d\n", ans);
28     }
29     return 0;
30 }

HDU 1536 S-Nim

题意:

给出一个集合 S 表示游戏中可选的数目,接下来给定 M 个游戏局面即 N 堆物品的大小。两人轮流选择一堆取数 只能取 ∈S 的数目,取走最后一个胜。判断游戏局面是先手胜还是后手胜。

题目给出了SG函数的用途和求法。

解题思路:

SG函数模板。

AC code:

 1 #include <bits/stdc++.h>
 2 #define inc(i, j, k) for(int i = j; i <= k; i++)
 3 #define rep(i, j, k) for(int i = j; i < k; i++)
 4 #define F(x) ((x)/3+((x)%3==1?0:tb))
 5 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 #define MEM(i, j) memset(i, j, sizeof(i));
 9 #define gcd(i, j) __gcd(i, j)
10 using namespace std;
11 const int MAXN = 2e3+10;
12 const int MM = 1e4+5;
13 int S[MAXN], sg[MM];
14 int vis[MM];
15 string ans;
16
17 void getsg(int n)
18 {
19     sg[0] = 0;
20     memset(vis, -1, sizeof(vis));
21     inc(i, 1, MM){
22         inc(j, 1, n){
23             if(S[j] > i) break;
24             vis[sg[i-S[j]]] = i;
25         }
26 //        puts("zjj");
27         int k = 0;
28         while(vis[k] == i) k++;
29         sg[i] = k;
30     }
31 }
32
33 int main()
34 {
35     int N, M, K, tp, res;
36
37     while(~scanf("%d", &N) && N){
38         ans = "";
39         inc(i, 1, N) scanf("%d", &S[i]);
40         //inc(i, 1, N) printf("%d ", S[i]);
41         sort(S+1, S+N+1);
42         getsg(N);
43 //        puts("zjj");
44         scanf("%d", &K);
45         while(K--){
46             scanf("%d", &M);
47 //            scanf("%d", &res);
48             res = 0;
49             inc(i, 1, M){
50                 scanf("%d", &tp);
51                 res^=sg[tp];
52             }
53             if(res == 0) ans+=‘L‘;
54             else ans+=‘W‘;
55         }
56         cout << ans << endl;
57     }
58
59     return 0;
60 }

原文地址:https://www.cnblogs.com/ymzjj/p/10731673.html

时间: 2024-10-11 03:03:23

博弈题目小结的相关文章

博弈论类题目小结——转载

出处http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 首先当然要献上一些非常好的学习资料: 基础博弈的小结:http://blog.csdn.net/acm_cxlove/article/details/7854530 经典翻硬币游戏小结:http://blog.csdn.net/acm_cxlove/article/details/7854534 经典的删边游戏小结:http://blog.csdn.net/acm

博弈初级小结

一.巴什博奕!!!! 巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜. 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜.因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者

ACM -二分图题目小结(更新中)

暂时只包括与最大匹配相关的问题. 求最大独立集,最小路径覆盖等等大多数题目都可以转化为求最大匹配用匈牙利算法解决. 1.最大匹配(边集) 此类问题最直接,直接用匈牙利算法即可. HDU 2063  过山车 http://acm.hdu.edu.cn/showproblem.php?pid=2063 二分图最大匹配模版题. ZOJ 1654 - Place the Robots http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode

状态压缩题目小结

1.POJ - 3254 Corn Fields 题目大意:有一个n*m的草地(草地上有的是沼泽),现在要分配牛去上面吃草,要求每头牛不能相邻(不能有公共边),问有多少种分配方案,一头牛都不分配也算一种分配方案 解题思路:这是碰到的第一道比较另类的压缩 1.首先考虑一下,每一行该怎么分配牛才不会让他们相邻,可以用状态压缩,0表示不放牛,1表示放牛,枚举一下有多少种可行的方案并纪录下来 2.接着考虑一下,因为不能相邻,而相邻的行之间又会相互影响. 考虑到第一行是比较特殊的,可以先枚举第一行的解决方

CDQ分治题目小结

CDQ分治属于比较特殊的一类分治,许多问题转化为这类分治的时候,时空方面都会有很大节省,而且写起来没有这么麻烦. 这类分治的特殊性在于分治的左右两部分的合并,作用两部分在合并的时候作用是不同的,比如,通过左半部分的影响来更新右半部分,所以分治开始前都要按照某一个关键字排序,然后利用这个顺序,考虑一个区间[l, r]的两部分间的影响.感觉说的太多,还是不如具体题目分析,而且题目也不尽相同,记住几句话是没什么用的. 练习地址: http://vjudge.net/contest/view.actio

组合博弈入门小结(更新中)

这几天开始学习博弈,发现这一块是个难啃的骨头.以下是我从网上收集的资料汇总: 我国民间有个古老的游戏:就是有物品若干堆,(物品可以是火柴,围棋都可以).两个人轮流从堆中取若干件,规定取光物体者为胜.这个就是我们今天要研究的组合游戏. 组合游戏定义: 1.有且仅有两个玩家    2.游戏双方轮流操作    3.游戏操作状态是个有限的集合(比如:取石子游戏,石子是有限的,棋盘中的棋盘大小的有限的)  4.游戏必须在有限次内结束  5.当一方无法操作时,游戏结束. 现在我们来研究如何取胜: (一)巴什

codeforeces近日题目小结

upd:2019-12-13 题目源自codeforces的Round_602_div1+2, Round_603_div2, Educational_Round_77 Round_603/F: 考虑一个经典dp状态定义, dp[i][j]代表上面一个树的最后一个被选取的叶节点编号是i 下面的树最后一个被选取的叶节点编号是j且 i != j 那么我们需要考虑第 max(i, j) + 1 个点是选择上下哪棵树的点 这个代价其实就是比较好求的了 Round_602_div1/E: 我直接参考的最短

前端笔试题目小结--获取输入参数用户名;查询URL字符串参数

编写一个JavaScript函数getSuffix,用于获得输入参数的后缀名.如输入abc.txt,返回txt. 1 str1 = "abc.txt"; 2 function getSuffix(str) 3 { 4 var index =str.indexOf("."); 5 if(index !=-1) 6 { 7 str = str.substring(index+1); 8 } 9 else{ 10 str = "not find"; 1

排序计数类题目小结

考虑到每次出哒哒哒操作,最少多少次操作使数组有序这一类题我都错的很惨,小小地总结一下 1.交换相邻位置的点->求逆序对(火柴排队,10.30noip模拟赛T1),有效的操作一定使得逆序对减少一个 2.交换任意位置->转化为置换(10.30noip模拟赛T1),置换内交换只需要置换中点个数次 3.每次可以把一个数扔到最前面->(HDU5500,noip模拟赛11.12T1)官方题解: 把这题的模型简化一下,有一个1→n的排列形成的数列,我们要用最少的操作次数把这个数列排序,每次操作都是把一