动态规划法----多边形游戏问题
https://blog.****.net/jarvischu/article/details/6007014
一、题目
给出一个多边形,满足:
1. 每个顶点是一个数值
2. 每条边是一个符号
我们将某个边断开,形成一条数值和符号组成的链,然后计算这条链的值。
1· 可以选择任意一条边断开。
2.求链的值时,可以不必按运算符的优先级顺序,任意选择先后
题目的要求是得到最大的值
二、示例
三、分析
1. 如上图,我们将图的信息保存如下:
顶点数:REAL_SIZE = 3
顶点:v[3] = {1,2,3}
边: op[3] = {'+','x','+'}
2. 假如我们从 边i 断开,则形成了链
v[i],op[i+1],v[i+1],op[i+2] .....v[i+s-1],op[s],v[i+s]...op[i-1],v[i-1]
计算得到其最大值,题目要求的最大值,也就是分别将每个边断开后,能得到的每条链的最大值中的最大的。
3. 为了计算方便,我们记:
p[i,j] 表示从顶点i开始,包括j个顶点的链
m[i,j,0]表示这条链的最小值
m[i,j,1]表示这条链的最大值
这样 i 从 0到REAL_SIZE 的所有 m[i,REAL_SIZE,1]中最大的就是题目要的结果
4. 将p[i,j]在op[i+s]处断开,则形成两条链p[i,s],和p[i+s,j-s]
得到p[i,s]和p[i+s,j-s]的最小值和最大值,就可以得到p[i,j]在s处断开的最大值最小值
当s 从1开始到 j-1,分别得到 对应的断开方法的最值,从这些最值中选择最小和最大的作为m[i,j,0]和m[i,j,1]
四、代码如下
- #include<stdio.h>
- //--------------------------预定义与全局变量------------------------------------
- #define MAX_VETEX_SIZE 20 //程序能接受的最大顶点数目
- int REAL_SIZE; //程序中实际的顶点数目
- int m[MAX_VETEX_SIZE][MAX_VETEX_SIZE+1][2]; //保存最大最小值(第二维表示链中顶点个数)
- int v[MAX_VETEX_SIZE]; //顶点(数值)
- char op[MAX_VETEX_SIZE]; //边(符号)
- //--------------------------初始化m数组-----------------------------------------
- void init_m(){
- int i;
- for(i=0;i<REAL_SIZE;i++){
- m[i][1][0] = v[i]; //链中只有一个顶点i
- m[i][1][1] = v[i];
- }
- }
- //-----------------------返回四个数中的最值---------------------------------------------
- void getMin_Max(int n1,int n2,int n3,int n4,int* min,int* max){
- //返回四个操作数中的最大最小值
- *min = (n1>n2)?((n2>n3)? (n3>n4? n4:n3):(n2>n4? n4:n2))
- :((n1>n3)? (n3>n4? n4:n3):(n1>n4? n4:n1));
- *max = (n1<n2)?((n2<n3)? (n3<n4? n4:n3):(n2<n4? n4:n2))
- :((n1<n3)? (n3<n4? n4:n3):(n1<n4? n4:n1));
- }
- //-----------------------获取有断点的最大最小值--------------------------------------
- void minMax(int i,int s,int j,int* minf,int* maxf){
- //p[i,j]从s处断开的最大值maxf 与 最小值minf
- // int e[4]; //ac,ad,bc,bd 的值
- int a,b,c,d,r;
- a = m[i][s][0]; //a 保存从i 到 i+s顶点构成链的最小值
- b = m[i][s][1];
- r = (i+s)%REAL_SIZE;
- c = m[r][j-s][0];
- d = m[r][j-s][1];
- //printf("i=%d; s=%d; j=%d; r=%d/n",i,s,j,r);
- if(op[r] == '+'){ //处理加号
- *minf = a+c;
- *maxf = b+d;
- }
- else{ //处理乘法
- getMin_Max(a*c,a*d,b*c,b*d,minf,maxf); //获取ac,ad,bc,bd 的最大最小值
- }
- }
- //------------------------------获取结果-------------------------------------------------
- int Poly_Max(){
- int minf,maxf,temp;
- int i,j,s;
- for(j=2;j<=REAL_SIZE;j++){ //控制每个链中的顶点个数
- for(i=0;i<REAL_SIZE;i++){ //控制每个链中的顶点的起始位置
- for(s=1;s<j;s++){
- minMax(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;
- }
- //此时已经获得了从i到i+j的顶点所有s对应的值中最大和最小
- }
- }
- //求所有长度为REAL_SIZE个顶点的链中,值最大的
- temp = 0;
- for(i=1;i<REAL_SIZE;i++){
- if(m[i][REAL_SIZE][1] > m[temp][REAL_SIZE][1]){
- temp = i;
- }
- }
- return m[temp][REAL_SIZE][1];
- }
- //---------------------------------主函数--------------------------------------------------
- void main(){
- int i =0;
- scanf("%d",&REAL_SIZE); //用户输入顶点数目
- for(i=REAL_SIZE-1;i>=0;i--){ //顶点和边信息
- scanf("%d %c",&v[i],&op[i]); //输入样例如下
- } //3
- //1 x 3 + 2 +
- init_m();
- printf("%d/n",Poly_Max()); //输出为 9
- }