多边形游戏
2017-03-29 14:11
99 查看
/* 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 = {1,3,-2,-3,5-6}; char op = {'+', '*', '*','+', '*', '+'}; int m [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] [1]; for (int i=1; i<n; i++) { if (m[i] [1] > maxf) maxf = m[i] [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]; } } }