近日领到了老师的期末作业 其中有这道 01 串博弈问题:

刚开始读题我也是云里雾里 但是精读数遍 “细品” 之后,我发现这是一个 “动态规划” 问题。好嘞,硬着头皮上吧。

分析问题:可知对每个人有两手选择 0 或 1。那么很自然的我们就可以用二叉树来储存每一个选择后的结果。对于本题 ,选择后的结果是还有多少01串未被抹除。所以我再每一个二叉树的节点上再生成一维向量组来保存我们还有那些串未被抹除。这样经过一系列暴力的循环运算后我们将得到一个储存着我们的结果的二叉树。之后的问题是:如何得到必胜方。这一点困扰了我不少时间。不过只要你逻辑清晰还是很容易可以知道:对于每一个节点来说,下一手的选择是对当前的博弈者最有利的选择。比如对亚当来说,选择0,必输,选择1,有可能会嬴,那么亚当绝对会选择1。理清了这个逻辑,加上之前我们已经运算出了博弈的所有结果,这样我们便可以从下往上,从子树反推根代表的必胜者。(这部分可能很绕。。。请多思考),这样我们再建立一个二维向量表,并将刚才所有博弈结果中的胜利者信息(第 i 手,是哪个根的子树)输入进去,然后暴力计算反推:)。虽然我们的方法看起来粗糙 、原始、血腥,任何一个算法老鸟看了都不屑一顾,但能抓住老鼠就是好猫啊!

ps:(之前再网上看过某前辈用的栈+类轻松解决问题,我这个自学c++的小白实在学不来。。。)

下面贴上代码:

 // 01串.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include<iostream>
#include <vector>
#include <math.h> using namespace std;
void Findwiner(vector<vector<int>>&n, vector<int>&a);
int Findwiner_i(vector<vector<int>>&n, int i);
int p = ;//全局变量 01 串的数量
constexpr auto len = ;//定义01串最大的长度 若31以上要将向量里的 int 换为long int!!!!!! int main()
{
cout << "输入串的数目:";
cin >> p; char a[len];
vector<int> w(p, );
vector<vector<int>> b(p);
for (int i = ; i < p; i++)
{
b[i].resize(len);
}
//将向量全部初始化为3,用来区分01串;
for (int i = ; i < p; i++)
{
for (int j = ; j < len; j++)
{
b[i][j] = ;
} }
//输入字符串 并将其值添加到向量中去。
cout << "初始化:" << endl;
for (int i = ; i < p; i++)
{
cout << "输入第" << i + << "串:";
cin >> a;
for (int j = ; j < len; j++)
{
if (((a[j] - '') == ) || ((a[j] - '') == ))
{
b[i][j] = a[j]-'';
}
else
{
break;
} } }
cout << endl;
cout << "输入为:"<<endl;
for (int i = ; i < p; i++)
{
for (int j = ; j < len; j++)
{
if ((b[i][j] == ) || (b[i][j] == ))
{
cout << b[i][j];
}
else
{
break;
}
}
cout << endl;
} Findwiner(b,w); cout << endl; for (int i = ; i < p; i++)
{
cout << w[i] << " ";
}
cout << endl;
cout << "winer: " << " start " << " end " << endl; cout << endl;
cout << endl;
for (int i = ; i < p; i++)
{
if (w[i] == )
{
if ((i == ) || (w[i - ] == ))
{
cout << "Eva: ";
}
if ((i == ) || (w[i - ] == ))
{
cout << " " << i+ << " ";
}
if (i != p - )
{
if (w[i + ] == )
{
cout << " " << i+ << " " << endl;
}
}
else
{
cout << " " << i+ << " " << endl;
}
}
if (w[i] == )
{
if ((i == ) || (w[i - ] == ))
{
cout << "Adam : ";
}
if ((i == ) || (w[i - ] == ))
{
cout << " " << i+ << " ";
}
if (i != p - )
{
if (w[i + ] == )
{
cout << " " << i+ << " " << endl;
}
}
else
{
cout << " " << i+ << " " << endl;
}
} } system("pause");
return ;
} void Findwiner(vector<vector<int>>&n,vector<int>&a)
{
int i = ; for (i=;i<p;i++)
{
a[i] = Findwiner_i(n,i+);
}
/*a[2] = Findwiner_i(n, 2 + 1);
system("pause");*/ } int Findwiner_i(vector<vector<int>>&n,int i)
{
vector<int> temp(i,);
vector<vector<vector<int>>> dpt(len + );
vector<vector<int>> dp(len + );
int sign1 = , sign2 = , sign3 = , winer = ;
for (int j = ; j < len+; j++)
{
dpt[j].resize(pow(, len + ));
dp[j].resize(pow(, len + ));
}
for (int j = ; j < len+; j++)
{
for (int k = ; k < pow(, len+); k++)
{
dpt[j][k].resize(i);
}
}
for (int j = ; j < i; j++)
{
dpt[][][j] = temp[j];
}
//运行动态规划 计算dpt表 将博弈的结果存在里面
for (int j = ; j < len; j++)
{
for (int k = ; k < pow(,j); k++)
{
for (int l = ; l < i; l++)
{
if (dpt[j][k][l] != )
{
if (n[l][j] == )
{
dpt[j + ][(k + ) * - ][l] = ;
dpt[j + ][(k + ) * - ][l] = dpt[j][k][l];
}
if (n[l][j] == )
{
dpt[j + ][(k + ) * - ][l] = dpt[j][k][l];
dpt[j + ][(k + ) * - ][l] = ;
}
if (n[l][j] == )
{
dpt[j + ][(k + ) * - ][l] = ;
dpt[j + ][(k + ) * - ][l] = ;
}
}
else //dpt[j][k][l]==0;
{
dpt[j + ][(k + ) * -][l] = dpt[j][k][l];
dpt[j + ][(k + ) * - ][l] = dpt[j][k][l];
}
}
}
} //===================================================================
//输出dpt 调试用
/*for (int j = 0; j < len + 1; j++)
{
for (int k = 0; k < pow(2, j ); k++)
{
for (int l = 0; l < i; l++)
{
cout << dpt[j][k][l];
}
cout << " " ;
}
cout << endl;
}*/
//===================================================================
//计算dp dp表表示在二叉树中胜利者的位置 经两次计算将胜利者的代号放入dp[0][0]中
for (int j = ; j <len; j++)
{
for (int k = ; k < pow(, j); k++)
{
sign1 = ;
sign2 = ;
sign3 = ;
for (int l = ; l < i; l++)
{
if (dpt[j][k][l] != )
{
sign1++;
}
if (dpt[j + ][(k + ) * - ][l] != )
{
sign2++;
}
if (dpt[j + ][(k + ) * - ][l] != )
{
sign3++;
}
}
if ((sign1 != )&&(sign2==)&&(sign3==))
{
if (j % == )
{
dp[j][k] = ;
}
if (j % == )
{
dp[j][k] = ;
}
}
}
} //========================================================================
//1 :adam 2:eva
for (int j = len - ; j > ; j--)
{
for (int k = ; k < pow(, j); k++)
{
sign1 = ceil((double)(k + ) / ) - ;
if (sign1 < )
{
sign1 = ;
}
if (dp[j][k] == )
{
if (dp[j - ][sign1] == )
{
dp[j - ][sign1] = dp[j][k];
}
if (dp[j - ][sign1] == )
{
dp[j - ][sign1] = dp[j][k];
}
if (dp[j - ][sign1] == )
{
if (j % == )
{
dp[j - ][sign1] = dp[j][k];
}
if (j % == )
{
dp[j - ][sign1] = dp[j - ][sign1];
} }
} if (dp[j][k] == )
{
if (dp[j - ][sign1] == )
{
dp[j - ][sign1] = dp[j][k];
}
if (dp[j - ][sign1] == )
{
dp[j - ][sign1] = dp[j][k];
}
if (dp[j - ][sign1] == )
{
if (j % == )
{
dp[j - ][sign1] = dp[j][k];
}
if (j % == )
{
dp[j - ][sign1] = dp[j - ][sign1];
} }
} if (dp[j][k] == )
{
dp[j - ][sign1] = dp[j - ][sign1];
}
}
}
//=============================================================
//输出dp 调式用
/* cout << endl << "dp:" << endl;
for (int j = 0; j < len + 1; j++)
{
for(int k=0;k<pow(2,j);k++)
{
cout << dp[j][k] << " ";
}
cout << endl;
}*/
winer = dp[][]; return winer;
}

  好了,到此本题结束,代码有点难看,不过凑合能用,希望能帮到以后的学弟学妹吧。:)

zerone 01串博弈问题的更多相关文章

  1. JZOJ P1847:找01串

    传送门 DP预处理+贪心 首先设$f[i][j]$表示长度为$i$的01串中有不大于$j$个1,然后显然 $f[i][j]=\sum_{k=1} ^{j} C[i][k]$ $C[i][j]=C[i- ...

  2. 洛谷P2727 01串 Stringsobits

    P2727 01串 Stringsobits 24通过 55提交 题目提供者该用户不存在 标签USACO 难度普及+/提高 提交  讨论  题解 最新讨论 这题的思路是啥啊!!!跪求- 题目背景 考虑 ...

  3. C++实现01串排序

    题目内容:将01串首先按长度排序,长度相同时,按1的个数从少到多进行排序,1的个数相同时再按ASCII码值排序. 输入描述:输入数据中含有一些01串,01串的长度不大于256个字符. 输出描述:重新排 ...

  4. 01串(dp)

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个, ...

  5. 【巧妙】【3-21个人赛】Problem C 01串

    Problem C Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Sub ...

  6. NYOJ-252 01串

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有"11"子串的这样的长 ...

  7. NYOJ 252 01串(斐波那契数列变形)

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个, ...

  8. COGS 862. 二进制数01串【dp+经典二分+字符串】

    862. 二进制数01串 ★   输入文件:kimbits.in   输出文件:kimbits.out   简单对比 时间限制:1 s   内存限制:128 MB USACO/kimbits(译 by ...

  9. 1415: 小ho的01串 [字符串]

    点击打开链接 1415: 小ho的01串 [字符串] 题目描述 有一个由0和1组成的字符串,它好长呀--------一望无际 恩,说正题,小ho的数学不太好,虽然是学计算机的但是看见0和1也是很头疼的 ...

随机推荐

  1. RF之目录结构、执行参数、用例标签 -6

    自动化项目的目录结构:        建议的目录结构... 以robot --pythonpath .  tc命令执行tc用例下面所有的用例 builtin库里面的Run Keywords方法实现初始 ...

  2. c++类的创建与使用

    c++类的创建与使用 前言: 之前一直对c++的类的创建与使用不太熟悉,有些概念还是有点模糊,借着这次休息的机会整理一下对应是知识点.如有不正确的地方还希望各位读者批评指正. 一.C++中public ...

  3. sklearn调用SVM算法

    1.支撑向量机SVM是一种非常重要和广泛的机器学习算法,它的算法出发点是尽可能找到最优的决策边界,使得模型的泛化能力尽可能地好,因此SVM对未来数据的预测也是更加准确的. 2.SVM既可以解决分类问题 ...

  4. MySQL操作之DDL

    目录 SQL语句的分类 DDL语句 SQL语句的分类 DDL(Data Definition Languages)语句:数据定义语言.这些语句定义了不同的数据段. 数据库.表.列.索引等数据库对象的定 ...

  5. 【剑指Offer面试编程题】题目1524:复杂链表的复制--九度OJ

    题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 输入: 输入可能包含多个测试样例,输入以EOF结束. 对于每个测试案例,输入的第 ...

  6. main.js index.html与app.vue三者关系详解

    main.js index.html与app.vue三者关系详解 2019年01月23日 11:12:15 Pecodo 阅读数 186   main.js与index.html是nodejs的项目启 ...

  7. PHP 函数的作用

    函数是为了封装方法,方便调用. 设计一个计算的代码函数.举个栗子 <?php /** * Created by PhpStorm. * User: 炜文 * Date: 2017/2/15 * ...

  8. shell和Makefile

    一.shell基础 1.shell介绍 shell是操作系统的终端命令行 意义:快速的编译多个.c文件 shell是一类编程语言 常用shell语言:sh.bash.csh.ksh.perl.pyth ...

  9. SIAMATIC S7-1200 中通过 Modbus RTU 如何读取地址范围 9999 到 65535 的输入字

    原文地址 说明 除了需要 STEP 7 >= V13 SP1 (TIA Portal) 的软件,还需要 S7-1200 CPU 固件版本 >= V4 (文章编号: 6ES721x-1xx4 ...

  10. 攻防世界web新手区(3)

    xff_referer:http://111.198.29.45:43071 打开网址,显示出这个页面: X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP, ...