问题描述:
多边形游戏是一个单人玩的游戏,开始时有一个由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;
}