博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UVALive 3668 A Funny Stone Game(博弈)
阅读量:4707 次
发布时间:2019-06-10

本文共 3501 字,大约阅读时间需要 11 分钟。

Description 

The funny stone game is coming. There are n piles of stones, numbered with 0, 1, 2,..., n - 1. Two persons pick stones in turn. In every turn, each person selects three piles of stones numbered ijk (i < jj$ \leq$k and at least one stone left in pile i). Then, the person gets one stone out of pile i, and put one stone into pile j and pile k respectively. (Note: if j = k, it will be the same as putting two stones into pile j). One will fail if he can't pick stones according to the rule.

David is the player who first picks stones and he hopes to win the game. Can you write a program to help him?

The number of piles, n, does not exceed 23. The number of stones in each pile does not exceed 1000. Suppose the opponent player is very smart and he will follow the optimized strategy to pick stones.

Input

Input contains several cases. Each case has two lines. The first line contains a positive integer 
n ( 
$ \leq$n$ \leq$ 23) indicating the number of piles of stones. The second line contains 
n non-negative integers separated by blanks, 
S0,...Sn-1 ( 
$ \leq$Si$ \leq$ 1000), indicating the number of stones in pile 
0 to pile 
n - 1respectively.

The last case is followed by a line containing a zero.

 

Output

For each case, output a line in the format `` 
Game tijk". 
t is the case number. 
i
j and 
k indicates which three piles David shall select at the first step if he wants to win. If there are multiple groups of 
i
j and 
k, output the group with the minimized lexicographic order. If there are no strategies to win the game, 
i
jand 
k are equal to 
-1.
 
题目大意:有n堆石头,第i堆石头有Si个石头,每次可以从第i堆石头拿掉一个石头,然后在第j、k(i<j、k)上各放一个石头。两人轮流操作,不能操作的人算输,问先手第一步的必胜策略是什么,输出最小字典序的答案。
思路:利用SG函数来做。可以把每个石头看作是独立的游戏,那么对于某个在第i位的石头,它的后续状态是所有的在第j、k位的两个石头,这两个石头也是独立的游戏,那么sg[i] = mex{sg[j] ^ sg[k]},对于每个位置的sg[i]可以O(n^3)预先计算出来。
然后所有的石头的SG值异或若等于0则输出-1-1-1(对于每一个Si,若Si为奇数,则异或一次,若Si为偶数,则不异或,因为一个数异或偶数次,肯定是0,复杂度为O(n)),否则O(n^3)暴力枚举方案,若sg[i]^sg[j]^sg[k]^ans==0,则i、j、k是必胜方案,其中ans是所有石头SG值异或的结果。
就是一步操作i、j、k,sg[i]会变成sg[j]^sg[k],那么若原来的SG值为ans,又sg[i]^sg[j]^sg[k]^ans==0,那么新状态的SG值就为0(可以参考NIM博弈的证明)。
 
代码(3MS):
1 #include 
2 #include
3 #include
4 #include
5 using namespace std; 6 7 const int MAXN = 23; 8 9 int sg[MAXN + 5];10 bool mex[MAXN * MAXN];11 int n, s[MAXN];12 13 void build_sg() {14 for(int i = MAXN - 1; i >= 0; --i) {15 memset(mex, 0, sizeof(mex));16 for(int j = i + 1; j < MAXN; ++j) {17 for(int k = j; k < MAXN; ++k) mex[sg[j] ^ sg[k]] = true;18 }19 for(int j = 0; ; ++j)20 if(!mex[j]) {sg[i] = j; break;}21 }22 }23 24 void solve() {25 int ans = 0, *sg = ::sg + MAXN - n;26 for(int i = 0; i < n; ++i) ans ^= sg[i] * (s[i] & 1);27 if(ans == 0) {28 printf(" -1 -1 -1\n");29 return ;30 }31 for(int i = 0; i < n; ++i) {32 if(s[i] == 0) continue;33 for(int j = i + 1; j < n; ++j) {34 for(int k = j; k < n; ++k) {35 if((sg[i] ^ sg[j] ^ sg[k] ^ ans) == 0) {36 printf(" %d %d %d\n", i, j, k);37 return ;38 }39 }40 }41 }42 }43 44 int main() {45 build_sg();46 int cnt = 0;47 while(scanf("%d", &n) != EOF && n) {48 for(int i = 0; i < n; ++i) scanf("%d", &s[i]);49 printf("Game %d:", ++cnt);50 solve();51 }52 }
View Code

 

转载于:https://www.cnblogs.com/oyking/p/3533483.html

你可能感兴趣的文章
Vue疑难杂症
查看>>
spring boot 错误处理之深度历险
查看>>
MySQL对于有大量重复数据表的处理方法
查看>>
Android应用开发学习笔记之多线程与Handler消息处理机制
查看>>
ubuntu 设置环境变量
查看>>
jquery之别踩白块游戏的实现
查看>>
索引的分类--B-Tree索引和Hash索引
查看>>
Python学习笔记——参数axis=0,1,2...
查看>>
kivy学习三:打包成window可执行文件
查看>>
兄弟连PHP培训教你提升效率的20个要点
查看>>
【快报】基于K2 BPM的新一代协同办公门户实践交流会
查看>>
关于MySQL的行转列的简单应用
查看>>
Queue 队列的用法
查看>>
CDM常用命令
查看>>
游戏开发中常用的设计模式
查看>>
Linux 中/etc/profile、~/.bash_profile 环境变量配置及执行过程
查看>>
JAVA:图形之利用FontMetrics类居中
查看>>
使用rsync同步目录
查看>>
[读码时间] for循环遍历设置所有DIV块元素背景色为红色
查看>>
网页调用迅雷下载文件
查看>>