题解 | #小游戏#

小游戏

http://www.nowcoder.com/practice/78f4c4bbd759422e9f4e33d7dada347b

对答案代码做了注释,只能说,这道题目没有AC才是真正的AC。

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <list>
#include <set>
#include <cmath>
#include <cstring>
#include "stdlib.h"
#include <iomanip>
#include <unordered_map>
#include <sstream>

using namespace std;


class node {
public:
    long long x, y;

    node(long long x, long long y) {
        this->x = x;
        this->y = y;
    }

    bool operator==(const node& p) const {
        return x == p.x && y == p.y;
    }
};

namespace std {
    template<>
    struct hash<node> {
        std::size_t operator()(const node& key) const {
            using std::size_t;
            using std::hash;

            return (hash<long long>()(key.x) ^ (hash<long long>()(key.y) << 1));
        }
    };
}
void myfind(long long na, long long nb);

unordered_map<node, int> m;
long long a, b, n;
/*
* 题目有点问题,第一回合A实际上没有操作,也就是真正开始的人是B
* 另外程序有很多逻辑问题,这个代码应该就是出题的人写的,只有这样才能跟答案完全匹配上
*/
int main() {
    int t;

    cin >> t;
    while (t--) {
        cin >> a >> b >> n;
        //不清楚这一步逻辑是什么。我猜测是这一步会导致递归时时间太久,所以作者把他特殊处理了。
        if (a == 1 && n == 86936814) {
            cout << "B" << endl;
            continue;
        }
        //开始就已经不能操作了,按照实际第一人是B处理,那么就是A赢了
        if (pow(a, b) >= n) {
            cout << "A" << endl;
            continue;
        }
        //a=1是需要特殊处理的,
        // 1)如果(a+1)^b不满足要求,那么两个人都只会去增加b,导致平局
        // 2)如果满足要求,由于递归函数需要处理1^(b+k)次导致死循环,所以就把a+1=2,然后考虑对家的输赢情况。
        // 这边需要注意的是,其实还是有问题,题目说是最优的解,那么我选择a+1求得发现我输定了,那我是不是应该这一步选择b+1呢?
        // 然后把问题转给对家,但这样子代码就很难写了。因为对家也陷入同样的一个问题。
        if (a == 1) {
            if (pow(a + 1, b) <= n) {
                m.clear();
                node p(a + 1, b);
                m[p] = 0;
                myfind(a + 1, b);
                if (m[p] == 2) cout << "A" << endl;
                if (m[p] == 1) cout << "B" << endl;
                if (m[p] == 3) cout << "A&B" << endl;
            }
            else cout << "A&B" << endl;
            continue;
        }

        m.clear();
        node p(a, b);
        m[p] = 0;
        myfind(a, b);
        if (m[p] == 1) cout << "A" << endl;
        if (m[p] == 2) cout << "B" << endl;
        if (m[p] == 3) cout << "A&B" << endl;
    }


}
/*
* map[i]=0,1,2,3分别意味着,i节点初始化,能赢,会输,平局
* 
*/
void myfind(long long na, long long nb) {
    node p(na, nb);
    node p1(na, nb + 1);
    node p2(na + 1, nb);
    //如果当前结果已经输定了,那么把当前节点标记为2
    if (pow(na, nb) >= n) {
        m[p] = 2;
        return;
    }
    //如果节点不存在,初始化
    if (m.find(p1) == m.end()) m[p1] = 0;
    //如果这个节点不知道是赢得还是输的,那么递归一下
    if (m[p1] == 0) myfind(na, nb + 1);
    //如果子节点赢了,意味着对家赢了,那么自家就输了
    if (m[p1] == 1) {
        m[p] = 2;
        return;
    }
    //同样的道理处理另一个节点
    if (m.find(p2) == m.end()) m[p2] = 0;
    if (m[p2] == 0) myfind(na + 1, nb);
    if (m[p2] == 1) {
        m[p] = 2;
        return;
    }
    //对面两种情况都输,那么自家就赢了
    //
    // 
    // 这边有没有考虑p1平局,p2输和p1输,p2平局的情况
    // 或者说,为什么以上两种情况下,就一定是平局了呢?
    // 我感觉这边应该是或(||)而不是(&&),因为,你只要两种取法里面选择你能赢的取法不就好了吗?
    // 
    // 
    if (m[p1] == 2 && m[p2] == 2) {
        m[p] = 1;
        return;
    }
    
    //不会输也不会赢,就是平局,其实这边有问题的。
    m[p] = 3;

}

全部评论

相关推荐

点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务