zoukankan      html  css  js  c++  java
  • [杂项/无聊向]《美食大战老鼠》强卡最优策略搜索代码(非玩家勿入)

    最近常登《美食大战老鼠》这款沙雕游戏,不得不赞叹道里面的卡片强化系统真的****。为了最大化用有限卡强化出高星卡的成功概率,我就写了这么个大暴力程序。什么?!你不懂什么叫用最优策略最大化最终成功的概率?!怪我咯?……

    算法方面,哪有什么算法,直接上个无聊的大 dp 就完事儿了,状态通过哈希来存。

    用下面的代码实际操作了几次后感觉最优策略似乎有规律可循,所以应该还有提速空间。代码本身也有一些可优化的地方,不过懒得改了。

    基本使用方式:先输入 (n) 表示你已有的卡片数量,再输入 (n) 个数表示 (n) 张卡片的星级(顺序可任意),最后输入一个数表示你希望强化出的卡片星级。每一步程序都会输出最终成功概率以及当前的最优决策,按要求执行反馈即可。

    注意事项:

    1. 此代码未对任何非法操作做判断,所以请尽量保证输入合法(比如,不要出现希望强化出的卡片星级低于已有卡片的情况)
    2. 由于算法过于暴力,所以卡片数量不宜太多(最好不超过 (50) 张)
    3. 由于未找到 15 星上 16 星强化对应的概率,因此下面的代码只适用于 15 级以下的强化(我并不知道强化的基本概率的计算公式,所以只能打表)
    4. 下面的概率表默认强化用卡为高耗能卡(你应该明白是什么意思)
    5. 强化默认所使用的是同一种四叶草(对应的程序语句为const double mul = 1.0;mul表示四叶草对应的概率倍数,这里的1.0为不使用四叶草的情况,使用 1 级四叶草则将1.0改为1.2,以此类推)
    6. 可能有bug

    暂时留坑,以后这程序的功能会更加完善,大体准备再修改以下内容:

    • 加入同时用多张卡强化一张卡的操作
    • 加入 VIP 等级以及公会合成屋的强化概率加成
    • 更改输入格式(目前一个星级一个星级地输入的方式在数量多时会显得很麻烦)
    • 可选择查看当前各星级卡的剩余数量(以验证程序执行是否与当前实际情况同步,纯黑箱操作有时候会忘了当前操作是否执行)
    • 进行一些细节的优化

    下面的内容是不会更改的,这辈子都不会更改的

    1. 允许使用不同的四叶草(如果加入不同种类的四叶草的话,状态数量会大大增加,程序的处理能力上限也会大大降低)
    2. 可判断非法操作(谨慎就好,这个功能是绝对不会有的

    以后有时间再更。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1000000;
    const int M = 16;
    const int mod = 998244353;
    const double mul = 1.0;
    const double eps = 1e-8;
    
    int n, all, goal;
    double p[M][M], f[N];
    bool visit[N];
    map<int, int> hash_t;
    pair<int, vector<int>> best[N];
    
    void init() {
      p[0][0] = 1;
      p[1][1] = 1;
      p[2][2] = 0.9683;
      p[3][3] = 0.6858;
      p[4][4] = 0.495;
      p[5][5] = 0.3958;
      p[6][6] = 0.3192;
      p[7][7] = 0.2642;
      p[8][8] = 0.22;
      p[9][9] = 0.135;
      p[10][10] = 0.125;
      p[11][11] = 0.116;
      p[12][12] = 0.107;
      p[13][13] = 0.101;
      p[14][14] = 0.095;
    
      p[1][0] = 0.88;
      p[2][1] = 0.792;
      p[3][2] = 0.55;
      p[4][3] = 0.4033;
      p[5][4] = 0.33;
      p[6][5] = 0.264;
      p[7][6] = 0.212;
      p[8][7] = 0.132;
      p[9][8] = 0.045;
      p[10][9] = 0.044;
      p[11][10] = 0.043;
      p[12][11] = 0.0398;
      p[13][12] = 0.0367;
      p[14][13] = 0.0336;
    
      p[2][0] = 0.6083;
      p[3][1] = 0.4292;
      p[4][2] = 0.2417;
      p[5][3] = 0.2008;
      p[6][4] = 0.132;
      p[7][5] = 0.106;
      p[8][6] = 0.06;
      p[9][7] = 0.022;
      p[10][8] = 0.018;
      p[11][9] = 0.017;
      p[12][10] = 0.0156;
      p[13][11] = 0.0141;
      p[14][12] = 0.0126;
    }
    
    // p = p1 + p2/3 + p3/3
    double get(int i, vector<int> j) {
      reverse(j.begin(), j.end());
      double result = 0;
      result += p[i][j[0]];
      if (j.size() > 1) {
        result += p[i][j[1]] / 3;
      }
      if (j.size() > 2) {
        result += p[i][j[2]] / 3;
      }
      return min(result * mul, 1.);
    }
    
    pair<bool, int> encode(vector<int> info) {
      bool exist = true;
      int base = 0;
      for (auto x : info) {
        base = (base * 233ll + x) % mod;
      }
      if (!hash_t.count(base)) {
        exist = false;
        hash_t[base] = ++all;
        if (info[goal]) {
          visit[all] = true;
          f[all] = 1;
        }
      }
      return make_pair(exist, hash_t[base]);
    }
    
    void strengthen(int i, vector<int> j, vector<int>& number, bool success = true) {
      --number[i];
      for (auto x : j) {
        --number[x];
      }
      if (success) {
        ++number[i + 1];
      } else {
        ++number[i - (i > 5)];
      }
    }
    
    int count(vector<int> number) {
      int result = 0;
      for (auto x : number) {
        result += x;
      }
      return result;
    }
    
    double dp(vector<int> number) {
      int id = encode(number).second;
      if (visit[id]) {
        return f[id];
      }
      visit[id] = true;
      if (count(number) == 1) {
        return f[id] = 0;
      } else {
        double& answer = f[id]; 
        vector<int> here = number;
        for (int i = 0; i < 15; ++i) {
          if (!number[i]) {
            continue;
          }
          --number[i];
          // 1->x
          for (int j = max(0, i - 2); j <= i; ++j) {
            if (number[j]) {
              vector<int> array1 = here, array0 = here, t1(1);
              t1[0] = j;
              strengthen(i, t1, array1);
              strengthen(i, t1, array0, false);
              double prob = get(i, t1);
              double foo = dp(array1) * prob + dp(array0) * (1 - prob);
              if (foo > answer) {
                answer = foo;
                best[id] = make_pair(i, t1);
              }
            }
          }
          // 2->x
          for (int j = max(0, i - 2); j <= i; ++j) {
            if (number[j]) {
              --number[j];
              for (int k = j; k <= i; ++k) {
                if (number[k]) {
                  vector<int> array1 = here, array0 = here, t2(2);
                  t2[0] = j;
                  t2[1] = k;
                  strengthen(i, t2, array1);
                  strengthen(i, t2, array0, false);
                  double prob = get(i, t2);
                  double foo = dp(array1) * prob + dp(array0) * (1 - prob);
                  if (foo > answer) {
                    answer = foo;
                    best[id] = make_pair(i, t2);
                  }
                }
              }
              ++number[j];
            }
          }
          // 3->x
          for (int j = max(0, i - 2); j <= i; ++j) {
            if (number[j]) {
              --number[j];
              for (int k = j; k <= i; ++k) {
                if (number[k]) {
                  --number[k];
                  for (int l = k; l <= i; ++l) {
                    if (number[l]) {
                      vector<int> array1 = here, array0 = here, t3(3);
                      t3[0] = j;
                      t3[1] = k;
                      t3[2] = l;
                      strengthen(i, t3, array1);
                      strengthen(i, t3, array0, false);
                      double prob = get(i, t3);
                      double foo = dp(array1) * prob + dp(array0) * (1 - prob);
                      if (foo > answer) {
                        answer = foo;
                        best[id] = make_pair(i, t3);
                      }
                    }
                  }
                  ++number[k]; 
                }
              }
              ++number[j];
            }
          }
          ++number[i];
        }
        return answer;
      }
    }
    
    int main() {
      init();
      cin >> n;
      vector<int> number(16);
      for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        ++number[x];
      }
      cin >> goal;
      //freopen("log.txt", "w", stdout);
      cout << "probability: " << setprecision(10) << dp(number) << '
    ';
      //assert(all < N);
      //cerr << all << '
    ';
      if (dp(number) > eps) {
        while (1) {
          int id = encode(number).second;
          cout << "the best choice is: strengthen " << best[id].first << " with {";
          vector<int>& t = best[id].second;
          for (int i = 0; i < t.size(); ++i) {
            if (i) {
              cout << ", ";
            }
            cout << t[i];
          }
          cout << "}." << '
    ';
          cout << "have you succeeded? (input 1 for success and 0 for failure)" << '
    ';
          string inf;
          cin >> inf;
          strengthen(best[id].first, best[id].second, number, inf == "1");
          id = encode(number).second;
          if (f[id] == 1) {
            cout << "congratulation!" << '
    ';
            break;
          } else if (f[id] < eps) {
            cout << "sorry, it's impossible now." << '
    ';
            break; 
          } else {
            cout << "probability now: " << setprecision(10) << f[id] << '
    ';
          }
        }
      } else {
        cout << "it's impossible." << '
    ';
      }
      cout << "done." << '
    ';
      return 0;
    }
    
  • 相关阅读:
    [SCOI2005]骑士精神
    [SCOI2005]超级格雷码
    [SDOI2013]淘金
    [SCOI2014]方伯伯的商场之旅
    P4317 花神的数论题
    RSA算法原理(一)
    PKI 笔记
    字符串解析运用-将字符串分解为多个整数,求各整数之和(华为oj)
    pycharm快捷键、常用设置、配置管理
    启动ipython notebook(jupyter)
  • 原文地址:https://www.cnblogs.com/ImagineC/p/12314105.html
Copyright © 2011-2022 走看看