计蒜客- BE, GE or NE 博弈论
链接:https://nanti.jisuanke.com/t/31454
题意:一个游戏根据途中不同的选择,对最终的分数有不同的影响,根据最终分数有三种结局:gd,bd,nd。现K和S一起玩这个游戏,K希望gd,S希望bd。有n次选择,每次选择可能有a,b,c三个选项,选择a,则分数+a,a=0代表没有a选项。选择b,则分数-b,b=0代表没有b选项。选择c,则分数*(-1),c=0代表没有c选项。他们轮流做选择,K先选。如果不能达到自己想要的结局,就尽量争取nd结局。保证每次选择至少有一个选项,分数范围是[-100 , 100]。问最终的结局。
思路:倒推。设置kwin,swin数组,分别代表对k有利的状态,对s有利的状态(并不总是必胜态)。在k的回合中,判断[-100,100]经过a,b,c选项,得到的cg值是否在swin中,只要有一个不再就把这个分数加入tt数组中,回合结束后将tt数组全部赋给kwin。在s的回合中同理。
#include <iostream> #include <string.h> #define maxn 1009 using namespace std; int n, m, k, l; int a[maxn], b[maxn], c[maxn]; int swin[201], kwin[201]; //who==1 判断k是否必胜, who==0 判断s是否必胜 bool iswin(bool who) { //仔细思考前四个for的范围,这是关键 if (who == 1) { if (n % 2 == 1) { for (int i = -100; i < k; i++) { swin[i + 100] = 1; } } else { for (int i = k; i <= 200; i++) { kwin[i + 100] = 1; } } } else { if (n % 2 == 1) { for (int i = -100; i < l; i++) { swin[i + 100] = 1; } } else { for (int i = l + 1; i <= 100; i++) { kwin[i + 100] = 1; } } } int cg, tt[201]; for (int i = n; i > 0; i--) { memset(tt, 0, sizeof tt); if (i % 2 == 1) { //k的回合 for (int ss = -100; ss <= 100; ss++) { if (a[i]) { cg = ss + a[i] + 100; if (cg > 200) cg = 200; if (!swin[cg]) tt[ss + 100] = 1; //这个分数经过a操作,不是s的有利态 } if (b[i]) { cg = ss - b[i] + 100; if (cg < 0)cg = 0; if (!swin[cg]) tt[ss + 100] = 1; } if (c[i]) { cg = ss * (-1) + 100; if (!swin[cg]) tt[ss + 100] = 1; } } for (int k = 0; k <= 200; k++) kwin[k] = tt[k]; } else {//s的回合 for (int ss = -100; ss <= 100; ss++) { if (a[i]) { cg = ss + a[i] + 100; if (cg > 200)cg = 200; if (!kwin[cg]) tt[ss + 100] = 1; } if (b[i]) { cg = ss - b[i] + 100; if (cg < 0) cg = 0; if (!kwin[cg]) tt[ss + 100] = 1; } if (c[i]) { cg = ss * (-1) + 100; if (!kwin[cg]) tt[ss + 100] = 1; } } for (int k = 0; k <= 200; k++) swin[k] = tt[k]; } } if (who == 1) { if (kwin[m + 100]) return 1; } else { if (!kwin[m + 100]) return 1; //注意‘!’ } return 0; } int main() { scanf("%d%d%d%d", &n, &m, &k, &l); for (int i = 1; i <= n; i++) { scanf("%d%d%d", &a[i], &b[i], &c[i]); } bool gd = iswin(1); bool bd = iswin(0); if (gd) printf("Good Ending"); else if (bd) printf("Bad Ending"); else printf("Normal Ending"); return 0; }