近日领到了老师的期末作业 其中有这道 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. sklearn实现决策树算法

    1.决策树算法是一种非参数的决策算法,它根据数据的不同特征进行多层次的分类和判断,最终决策出所需要预测的结果.它既可以解决分类算法,也可以解决回归问题,具有很好的解释能力.另外,对于决策树的构建方法具 ...

  2. ADO.NET基础必背知识

    DO.NET 由.Net Framework 数据提供程序和DataSet 两部分构成. .NET FrameWork 是 Connection  连接对象 Command   命令对象 DataRe ...

  3. java并发初探CountDownLatch

    java并发初探CountDownLatch CountDownLatch是同步工具类能够允许一个或者多个线程等待直到其他线程完成操作. 当前前程A调用CountDownLatch的await方法进入 ...

  4. MariaDB——数据库基础与sql语句

    数据库介绍 什么是数据库? 简单的说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织,存储的,我们可以通过数据库提供的多种方法来管理数据 ...

  5. 「Luogu2264」情书

    传送门 Luogu 解题思路 字符串模拟SB题,STL随便搞. 详情见代码. 细节注意事项 STL总得会吧. 参考代码 #include <algorithm> #include < ...

  6. 「PA2014」Kuglarz

    传送门 memset0好评 解题思路 其实这是一道图论题 不难发现,如果知道了 \(\sum1...i\) 和 \(\sum1...j\) 的奇偶性,那么就可以得知 \(\sum i+1...j\) ...

  7. 安装oracle客户端后,怎样设置电脑的环境变量?

    安装配置参考: http://www.haodaima.net/art/2854001 设置环境变量(修改PATH和TNS_ADMIN环境变量): 对于NLS_LANG环境变量, 最好设置成和数据库端 ...

  8. 2. 引用计数法(Reference Counting)

    1960年,George E. Collins 在论文中发布了引用计数的GC算法. 引用计数法意如了一个概念,那就是"计数器",计数器表示的是对象的人气指数, 也就是有多少程序引用 ...

  9. JAVA虚拟机:Java技术体系讲解(一)

    按照Java系统的功能划分为: 一.Java语言,即使用Java编程语言进行软件开发. 二.开发过程中使用的工具和API(API(Application Programming Interface,应 ...

  10. 15 SQL中的安全问题

    SQL中的安全问题     1.SQL注入         demo1:             SELECT * FROM user WHERE username = ? AND password ...