备忘录解决多边形游戏

问题描述:

多边形游戏是一个单人玩的游戏,开始时有一个由n个顶点构成的多边形。每个顶点被赋予一个整数值,每条边被赋予一个运算符“+”或“*”。所有边依次用整数从1到n编号。

  游戏第1步,将一条边删除。

  随后n-1步按以下方式操作:

  (1)选择一条边E以及由E连接着的2个顶点V1和V2;

  (2)用一个新的顶点取代边E以及由E连接着的2个顶点V1和V2。将由顶点V1和V2的整数值通过边E上的运算得到的结果赋予新顶点。

  最后,所有边都被删除,游戏结束。游戏的得分就是所剩顶点上的整数值。

  问题:对于给定的多边形,计算最高得分。

看了很多文章, 都没有用备忘录算法解决n后的问题,所以博主试着用备忘录基本思想撸了一个n后问题的备忘录版本。首先,简单说说什么是备忘录算法。备忘录方法是动态规划的变形。与动态规划算法一样,备忘录方法用表格保存已解决的子问题的答案,在下次需要解决此问题时,只要简单地查看该子问题的解答,而不必重新计算,从而减少算法的时间复杂度。与动态规划不同的是,备忘录方法的递归方式是自顶向下的,不同于动态规划的自底向上。

下面开始分析算法:

数据结构:

v[N+1]  存放顶点数值

op[N+1]  存放操作符

flag[N+1][N+1]   表示该段数据有没有写入,写入为1,否则为0

m[i][j] 表示该段的数据,i为起点,j为终点

place 限制返回范围


#include <iostream>
using namespace std;
#define  N 100
int v[N + 1];
int m[N + 1][N + 1];
char flag[N + 1][N + 1];
char op[N + 1];
int p;
int n;
int maxf;
int place = 1;
int fun(int i, int j, int k)
{
	if (op[j] == '+')
		return i + k;
	else return i*k;
}

int polyMax(int i, int j)
{
	if (i == j)
	{
		m[i][j] = v[i];
		return v[i];
	}
	if (flag[i][j] == 1&&i >= place&&j >= place)
	{
			return m[i][j];
	}
	
	int u = fun(polyMax(i, i), i, polyMax(i + 1, j));
	for (int k = i + 1; k < j; k++)
	{
		int t = fun(polyMax(i, k), k, polyMax(k + 1, j));
		if (t>u)
			u = t; 
	}
	m[i][j] = u;
	flag[i][j] = 1;
	return u;
}
void init()
{
	for (int i = 1; i <= 2 * n - 1; i++)
	for (int j = 1; j <= 2 * n - 1; j++)
	{
		m[i][j] = 0;
		flag[i][j] = 0;
	}
}
int main()
{
	int temp;
	cout << "请输入多边形顶点数:" << endl;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cout << "请输入多边形顶点" << i << "数值:" << endl;
		cin >> v[i];
		cout << "请输入多边形边" << i << "运算符:" << endl;
		cin >> op[i];
	}
	maxf  = polyMax(1, n);
	p = 1;
	for (int a = 2; a <= n; a++)
	{
		place++;
		v[n + a - 1] = v[a-1];
		v[a - 1] = 0;
		op[n + a - 1] = op[a - 1];
		temp = polyMax(a, n + a-1);
		if (temp > maxf)
		{
			maxf = temp;
			p = a;
		}
	}
	cout <<"首次删掉第"<<p<<"条边,结果最大:"<< maxf << endl;
	system("pause");
	return 0;
}

代码具体分析:

因为多边形游戏起点是不定的,现假设第一次删的是第4条边。


对于上图,我们要求的是m[1][4]的值

不难理解:m[1][4]=max{m[1][1]op[1]m[2][4],m[1][2]op[2]m[3][4],m[1][3]op[3]m[4][4]}

而m[1][1]的值就是一个点,就是它本身的值1

m[2][4]=max{m[2][2]op[2]m[3][4],m[2][3]op[3]m[4][4]}

同理m[3][4],m[1][3]的值也可以求得。

我们可以用一个表格来表示:


可以发现上层的值可以通过下层的值得到。最后得到的结果24是第一条边删去的是op[4]

而根据问题我们需要每个边都要算一遍,这时候只需要把顶点的数据处理一下就可以了

可以用v[5]来表示v[1]的值,op[5]=op[1],然后从2~5开始再算一遍,这样就可以算出第一次删掉的边是op[1]的情况

n条边执行n次循环再筛选出其中的最大值,这就是问题的解。

执行效果如图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值