多边形游戏问题

问题描述:

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

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

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

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

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

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

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

如下图:

  

解:

设所给的多边形的顶点和边的顺时针序列位

op[1], v[1], op[2], v[2]...,op[n], v[n],其中op代表存储操作符的第i条边,v为存储顶点数值的数组。

设p[i][j]为存储以i节点为起点,长度为j的链的运算结果最小值数组,则可知p[i][n]为多边形第i边断裂后形成的链的最高分值结果。假设在op[i+s]处发生了合并运算,则可以在op[i+s]处将链分割成两个子链p[i][s],和p[i+s][j-s]两条子链,这也是链结果运算的最优子结构。

对于操作符,当op[i+s]为+时,最高得分为两子链之和;当op[i+s]为*时,因为节点的赋值可以为整数,则我们要知道左右子链的最大最小值,分别相乘结果取到最大。

综上,多边形游戏问题满足最优子结构性质,是动态规划问题。

#include<iostream>
#include<cstdlib>
#define MAAX 1000
#define MIIN -1000
using namespace std;

int p;
int dot[MAAX];//多边形顶点的数值 数组 
char op[MAAX];//多边形边的操作符号数组 
int m[MAAX][MAAX][2];//第i个顶点/长度为j时/1最大0最小值 的 存储 
void minMax(int i, int s, int j);
int polyMax(int num); 

int main()
{
	int num, ans; 
	printf("输入多边形顶点数:");
	cin>>num;
	cout<<"输入顶点值和边的类型";
	for(int i=1; i<=num; i++)
	{
		cout<<"第"<<i<<"点:";
		cin>>dot[i];
		cout<<"第"<<i<<"边:";
		cin>>op[i]; 
	}
	for(int i=1; i<=num; i++)
	{
		for(int j=1; j<=num; j++)
		{
			m[i][j][0] = MAAX;
			m[i][j][1] = MIIN;
		}
	}
	for(int i=1; i<=num; i++)//长度为1时,链为单个节点,则值为节点本身权值 
	{
		m[i][1][0] = dot[i];
		m[i][1][1] = dot[i];
	}
	ans = polyMax(num);
	cout<<"最高得分为"<<ans<<endl; 
	cout<<"首次删除"<<p<<"边"<<endl; 
	return 0;
 } 
 
 void minMax(int i, int s, int j, int num)
 {
 	int minf, maxf;
 	int a = m[i][s][0];
 	int b = m[i][s][1];
 	int r = (i+s-1)%num +1;
 	int c = m[r][j-s][0];
 	int d = m[r][j-s][1];
 	int e[5];
 	if(op[r]=='+')//读到边操作符+时 
 	{
 		minf = a+c;
 		maxf = b+d;
 		if(m[i][j][0]>minf)
			m[i][j][0] = minf;
		if(m[i][j][1]<maxf)
			m[i][j][1] = maxf;
	 }
	else
	{
		e[1] = a*c;
		e[2] = a*d;
		e[3] = b*c;
		e[4] = b*d;
		minf = e[1];
		maxf = e[1];
		for(int k=1; k<=4; k++)
		{
			if(minf>e[k])
				minf = e[k];
			if(maxf<e[k])
				maxf = e[k];
		}
		if(m[i][j][0]>minf)
			m[i][j][0] = minf;
		if(m[i][j][1]<maxf)
			m[i][j][1] = maxf;
	}
 }
 
 int polyMax(int num)
 {
 	for(int length = 2; length<=num; length++)
 	{
 		for(int i = 1; i<=num; i++)
 		{
 			for(int s = 1; s<length; s++)//i+s处的边断开 
 			{
 				minMax(i, s, length, num);
			 }
		 }
	 }
	 int temp = MIIN;
	 p=1;
	 for(int i=1; i<=num; i++)
	 {
	 	if(temp<m[i][num][1])
	 	{
	 		temp = m[i][num][1];
	 		p=i;
		 }
	 	
	 	cout<<temp<<endl;
	 }
	 
	 return temp;
 }
 
 


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值