js算法:动态规划-多边形游戏


问题描述:

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

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

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

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

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

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

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

如下图:

  

数据输入:

第一行是一个整数N

第二行按照

边 顶点 边 顶点 …. 边 顶点

的顺序以此存放了N个顶点和N条边的标注信息。

问题求解:

  

  当把一条边去除除后,再把它拉直,那么这个问题就可以变成一条链。那么就和以前写的矩阵连乘有几分的相似,其实我们最后要求的是这个链的表达式算式结果的最大值。于是我们就可以想到可以用数组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]来存储链的节点, value[i][j][0]表示链的最大值,value[i][j][1]表示链的最小值。

如果看不懂上面,下面这个图形可能更好理解:

给出一个n个顶点的多边形,每个顶点是一个整数值, 每条边是运算符‘+’或‘*’,

第一步:将某个边断开,形成一条数值和符号组成的链

接下来的n-1步按以下方式操作:

(1)选择一条边及边连接的两个顶点v1,v2;

(2)用一个新的顶点代替上述边和顶点,其值为,v1,v2经中间的运算符运算后得到得数;

以n=7为例:


附上js代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
 <HEAD>
  <TITLE> 多边形游戏-动态规划 </TITLE>
  <META NAME="Generator" CONTENT="EditPlus">
  <META NAME="Author" CONTENT="">
  <META NAME="Keywords" CONTENT="">
  <META NAME="Description" CONTENT="">
  <script>
   var v=[1,2,3];//点;
   var op=['+','+','x'];//对应边的操作符
   var value=[];//备忘录 value[i][j][0] 起点为i,链长为j 最小值 value[i][j][1]为最大值
   //初始化值
   var len=v.length;
   for(var i=0;i<len;i++){//起点,
        value[i]=[];	
     for(var j=0;j<len;j++){//链长
	   value[i][j]=[];
	   if(j==0){
	      //链长为0,最大值,最小值均为顶点值  
	      value[i][0][0]=v[i];
		  value[i][0][1]=v[i];
	   }else{
	      value[i][j][0]=99999;
		  value[i][j][1]=-99999;
	   }
	 }
   }

   //开始计算
   for(var length=1;length<len;length++){//控制链长
       for(var start=0;start<len;start++){
	      for(var k=0;k<length;k++){
		    getMax(start,length,k);
		  }
	   }   
   }
   //输出结果(逐步去除某条边)
   var maxValue=value[0][len-1][1];
   for(var start=1;start<len;start++){
      maxValue=Math.max(maxValue,value[start][len-1][1]);
   }
   document.write("最大值为:"+maxValue);

   //拆分计算
   function getMax(start,length,k){
       var index=(start+k+1)%len;
	   var a=value[start][k][0];
	   var b=value[start][k][1];
	   var c=value[index][length-k-1][0];
	   var d=value[index][length-k-1][1];
	   // a<=m1<=b  c<=m2<=d
	   document.write("value["+start+"]["+k+"];value["+index+"]["+(length-k-1)+"]<br/>");
	   document.write("a="+a+";b="+b+";c="+c+";d="+d+"<br/>");
	   var min=value[start][length][0];
	   var max=value[start][length][1];
	   //document.write("max="+max+";min="+min+"<br/>");
	   if(op[index]=="+"){
          max=Math.max(max,b+d);
		  min=Math.min(min,a+c);
	   }
	   else if(op[index]=="x"){
	      max=Math.max(a*c,a*d,b*c,b*d);
		  min=Math.min(a*c,a*d,b*c,b*d);	    
	   }
	   value[start][length][0]=min;
	   value[start][length][1]=max;
	   document.write("value["+start+"]["+length+"];"+value[start][length]+"<br/>");
   }
   
   
  </script>
 </HEAD>

 <BODY>
  
 </BODY>
</HTML>

运行结果:
value[0][0];value[1][0]
a=1;b=1;c=2;d=2
value[0][1];3,3
value[1][0];value[2][0]
a=2;b=2;c=3;d=3
value[1][1];6,6
value[2][0];value[0][0]
a=3;b=3;c=1;d=1
value[2][1];4,4
value[0][0];value[1][1]
a=1;b=1;c=6;d=6
value[0][2];7,7
value[0][1];value[2][0]
a=3;b=3;c=3;d=3
value[0][2];9,9
value[1][0];value[2][1]
a=2;b=2;c=4;d=4
value[1][2];8,8
value[1][1];value[0][0]
a=6;b=6;c=1;d=1
value[1][2];7,8
value[2][0];value[0][1]
a=3;b=3;c=3;d=3
value[2][2];6,6
value[2][1];value[1][0]
a=4;b=4;c=2;d=2
value[2][2];6,6
最大值为:9 

本文文字部分参考了博客

动态规划算法——多边形游戏问题 

动态规划--多边形游戏




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值