多边形游戏

/*
  Name: 多边形游戏
  Copyright: 
  Author: 巧若拙 
  Date: 28-03-17 15:39
  Description: 
问题描述:
多边形游戏是一个单人玩的游戏,开始时有一个由n个顶点构成的多边形。每个顶点被赋予一个整数值,
每条边被赋予一个运算符“+”或“*”。所有边依次用整数从1到n编号。
游戏第1步,将一条边删除。
随后n-1步按以下方式操作:
(1)选择一条边E以及由E连接着的2个顶点V1和V2;
(2)用一个新的顶点取代边E以及由E连接着的2个顶点V1和V2。将由顶点V1和V2的整数值通过边E上的运算得到的结果赋予新顶点。
最后,所有边都被删除,游戏结束。游戏的得分就是所剩顶点上的整数值。
问题:对于给定的多边形,计算最高得分。

问题求解:
当把一条边去除除后,再把它拉直,那么这个问题就可以变成一条链。
那么就和以前写的矩阵连乘问题和凸多边形最优三角剖分相似,      
其实我们最后要求的是这个链的表达式算式结果的最大值。
于是我们就可以想到可以用数组p[i][j]来表示从点i开始,链长为j的算术表达式的最大值,用v[i]存储操作数,op[i]存储操作符。
如果这条链的最后一次合并运算在op[i+s]处发生(1≤s≤j-1),则可在op[i+s]处将链分割为2个子链p[i][s]和p[i+s][j-s]。
似乎这样再按照以前解决动态规划题目时的思路,就可以解决问题了。   
但是,我们再来考虑一下,由于有两种运算符+和x,并且操作数可能存在负数,
那么我们也必须考虑两个负数相乘的结果可能比两个正数要打,所以我们同时还需要记录每个链的最大和最小值,然后判断,
如果操作符为+的话,只需要两个链的最大值相加即可,如果操作符是x的话,那么必须把各种情况考虑进来,然后再求出最大值。
分析如下:
设m1是对子链p[i][s]的任意一种合并方式得到的值,而a和b分别是在所有可能的合并中得到的最小值和最大值。
m2是p[i+s][j-s]的任意一种合并方式得到的值,而c和d分别是在所有可能的合并中得到的最小值和最大值。
依此定义有a<=m1<=b,c<=m2<=d
(1)当op[i+s]='+'时,显然有a+c<=m<=b+d
(2)当op[i+s]='*'时,有min{ac,ad,bc,bd}<=m<=max{ac,ad,bc,bd}
换句话说,主链的最大值和最小值可由子链的最大值和最小值得到。
于是我就用数组chain_value[i][j][2]来存储链的节点, 
其中chain_value[i][j][0]表示链的最大值,chain_value[i][j][1]表示链的最小值。			   
*/
#include<iostream>

using namespace std;

int PloyMax(int i, int j, int n);//自顶向下,使用备忘录数组的动态规划算法  
int PloyMax_2(int n);//自顶向下,使用备忘录数组的动态规划算法 
void MinMax(int n, int i, int s, int j, int &minf, int &maxf);//求最大值和最小值 

const int INF = -999999; //自定义的负无穷大 
const int N = 6;
int v[N] = {1,3,-2,-3,5-6};
char op[N] = {'+', '*', '*','+', '*', '+'};
int m[N][N+1][2];    //m[i][j][0]和m[i][j][1]分别链p(i,j)的最小值和最大值

int main(int argc, char **argv)
{
 	for (int i=0; i<N; i++)//初始化 
 	{
		m[i][1][0] = m[i][1][1] = v[i];
    }
    
    cout << PloyMax_2(N) << endl; //自底向上的动态规划算法 
	
	for (int i=0; i<N; i++)//初始化 
 	{
		for (int j=2; j<=N; j++)
	 	{
		    m[i][j][0] = m[i][j][1] = INF;
		}
    }	
    int maxf = INF;
    for (int i=0; i<N; i++)
    {
	 	int f = PloyMax(i, N, N);//自顶向下,使用备忘录数组的动态规划算法 
	 	cout << "f=" << f << endl;
	 	if (f > maxf)
	 	   maxf = f;
	}
	cout << maxf << endl;
    
    system("pause");
    return 0;
}

int PloyMax(int i, int j, int n)//自顶向下,使用备忘录数组的动态规划算法  
{
    int e[4] = {0}; 
    int a, b, c, d, r, minf, maxf;
	for (int s=1; s<j; s++)
	{//先分别处理两个子问题 
	    if (m[i][s][0] == INF || m[i][s][1] == INF) 
	        PloyMax(i, s, n); 
	        
	    a = m[i][s][0], b = m[i][s][1];
	    r = (i+s) % n;
	    
	    if (m[r][j-s][0] == INF || m[r][j-s][1] == INF) 
	        PloyMax(r, j-s, n); 
	        
	    c = m[r][j-s][0], d = m[r][j-s][1];
	 //   cout << "i= " << i << " j= " << j << " s = " << s <<  " r = " << r << " : " << a << " " << b << " " << c << " " << d << endl; 
	    if (op[r] == '+')
		{
			minf = a + c;
			maxf = b + d;
		}
		else
		{
			e[0] = a * c;
			e[1] = a * d;
			e[2] = b * c;
			e[3] = b * d;
			minf = maxf = e[0];
			for (int k=1; k<4; k++)
			{
			 	if (e[k] < minf)	
			 	   minf = e[k];
		        else if (e[k] > maxf)	
			 	   maxf = e[k];
			}
		}
		if (m[i][j][0] == INF || m[i][j][0] > minf)
		   m[i][j][0] = minf;
					
		if (m[i][j][1] == INF || m[i][j][1] < maxf)
		   m[i][j][1] = maxf;
       //  cout << "m[" << i << "][" << j << "][0] = " << m[i][j][0] << "   " << "m[" << i << "][" << j << "][1] = " << m[i][j][1] <<endl;
	} 
	
	return m[i][j][1];
}

int PloyMax_2(int n)//自底向上的动态规划算法 
{
	int minf, maxf;
	
	for (int j=2; j<=n; j++)
	{
		for (int i=0; i<n; i++)
		{
			for (int s=1; s<j; s++)
			{
				MinMax(n, i, s, j, minf, maxf);
				if (m[i][j][0] > minf)
					m[i][j][0] = minf;
					
				if (m[i][j][1] < maxf)
					m[i][j][1] = maxf;
			} 
		}
	}
	
	maxf = m[0][n][1];
	for (int i=1; i<n; i++)
	{
		if (m[i][n][1] > maxf)
			maxf = m[i][n][1];
	}
	return maxf;
}

void MinMax(int n, int i, int s, int j, int &minf, int &maxf)//求最大值和最小值 
{
    int e[4] = {0}; 
	int a = m[i][s][0], b = m[i][s][1];
	int r = (i+s) % n;
	int c = m[r][j-s][0], d = m[r][j-s][1];
	
	if (op[r] == '+')
	{
		minf = a + c;
		maxf = b + d;
	}
	else
	{
		e[0] = a * c;
		e[1] = a * d;
		e[2] = b * c;
		e[3] = b * d;
		minf = maxf = e[0];
		for (int k=1; k<4; k++)
		{
		 	if (e[k] < minf)	
		 	   minf = e[k];
	        else if (e[k] > maxf)	
		 	   maxf = e[k];
		}
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值