计蒜客- 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;
}

 

posted @ 2018-09-11 21:11  casccac  阅读(441)  评论(0编辑  收藏  举报