石子合并问题

来源:互联网 发布:淘宝订单不能批量删除 编辑:程序博客网 时间:2024/05/17 07:14

问题描述:在一个圆形操场的四周摆放着n堆石子,现要将石子有次序的合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
动态规划引入:如果N-1 次合并的全局最优解包含了每一次的子问题的最优解,那么经这样的N-1次合并后的得分总和必然是最优的。因此我们需要引入动态规划来求出最优解。
假设有石头Ai,Ai+1,……,Ai+j-1共j堆需要合并,简记为A[i+0,i+j-1].如果设最后一次合并发生在Ak与Ak+1之间(i<=k <=i+j-1),则最后一个合并的得分为Ai,Ai+1,……,Ai+j-1堆石头的个数的总和记为sum(i,j).(不管你最后一次合并发生在哪个位置,sum(i,j)的值都是一样的)因此总的得分等于:A[i,k]+A[k+1,i+j-1]+tsum(i,j).
这里写图片描述
思路分析:
动态规划思路:
阶段:石子的每一次合并过程,先两两合并,再三三合并,最后N堆合并。
状态:每一阶段中各个不同合并方法的石子合并总得分用arr[j][i]表示。
决策:把当前阶段的合并方法细分成前一阶段已计算出的方法,选择其中的最优方案。
例:(3 4 6 5 4 2)
第一阶段:arr[0][1] =0,arr[1][1] =0,arr[2][1]=0,arr[3][1]=0,arr[4][1=0],arr[5][1]=0
第二阶段:两两合并的过程如下,其中sum(j,i)表示从j开始i个数的和。
arr[0][2]=arr[0][1]+arr[1][1]+sum(0,2) =7
arr[1][2]=arr[1][1]+arr[2][1]+sum(1,2) =10
arr[2][2]=arr[2][1]+arr[3][1]+sum(2,2) =11
arr[3][2]=arr[3][1]+arr[4][1]+sum(3,2) =9
arr[4][2]=arr[4][1]+arr[5][1]+sum(4,2) =6
arr[5][2]=arr[5][1]+arr[0][1]+sum(5,2) =5
第三阶段:三三合并可以拆分成两两合并,拆分方法有两种 ,前两个为一组或后两个为一组
arr[0][3]= arr[0][1]+arr[1][2]+sum(0,3)=23或arr[0][3]= arr[0][2]+arr[2][1]+sum(0,3)=20
arr[1][3]= arr[1][1]+arr[2][2]+sum(1,3)=26或arr[1][3]= arr[1][2]+arr[3][1]+sum(1,3)=25
第四阶段:四四拆分的拆分方法有三种,同理求出三种分法的得分。以后在第五阶段、第六阶段以此类推。
源代码:

package ws;import java.io.*;public class TsetPebbleDynamic {    //计算从 begin开始 ,合并n个数的得分    public  static int sum( int begin,int n,int numArr[]){        int total = 0;        int l = numArr.length;//6        for(int i = begin;i<begin+n;i++){            total = total+numArr[i%l];//对l取余实现石子尾成一起的效果。        }        return total;//将得分返回    }    public static void main(String[] args)throws Exception {        System.out.println("从input。txt文件中读取的数据是:3 7 6 4 2 5 8  并将其存入数组中。");        // TODO Auto-generated method stub        BufferedReader br = new BufferedReader(new FileReader("E:/input.txt"));//从文件中读取数据        BufferedWriter bw = new BufferedWriter(new FileWriter("E:/output.txt"));//向文件中写入数据        String s = null;//用于临时存放从文件中读取的字符串        String[] str = null;//将从文件中读取的字符串写入数组        int[][] arr = new int[100][100];//二维数组用来存放 最小值        int [][] arrMax = new int[100][100];//二维数组用来存放最大值        int temp=0;//临时存放数据        //从文件中读取字符串 分割后放入数组        while((s=br.readLine())!= null){            str = s.split(" ");         }        int num = str.length;//获取数组的长度        int numArr[] = new int[num];//一位数组 用来存放石子的数目        //将String 数组转换为 int类型写入数组        for(int i =0;i<num;i++){            numArr[i] = Integer.valueOf(str[i]);        }        //初始阶段,当为一堆时 初始化为0        for(int i= 0;i<num;i++){            arr[i][1] = 0;            }        //求最小值        //初始化多行进行合并        for(int i = 2;i<=num;i++){            //合并的起始位置            for(int j = 0;j<num;j++){                arr[j][i] = arr[j][1]+arr[(j+1)%num][i-1];//合并的起始位置                for(int k=2;k<i;k++){//开始进行分割                    temp = arr[j][k]+arr[(j+k)%num][i-k];//将后来的分割存入临时变量中,方便后来进行比较                    if(temp<arr[j][i])//两组数据进行比较,将最小的数值赋值给arr[j][i]                        arr[j][i]=temp;                }                arr[j][i]+=sum(j,i,numArr);//调用sum函数 计算出从j开始,合并i个数据的最小值                System.out.print("arr["+j+"]["+i+"] = "+arr[j][i]+" ");//将合并后的数据进行打印            }            System.out.println();        }        //求最大值 同理        for(int i = 2;i<=num;i++){            //合并的起始位置            for(int j = 0;j<num;j++){                arrMax[j][i] = arrMax[j][1]+arrMax[(j+1)%num][i-1];                for(int k=2;k<i;k++){                    temp = arrMax[j][k]+arrMax[(j+k)%num][i-k];                    if(temp>arrMax[j][i])                        arrMax[j][i]=temp;                }                arrMax[j][i]+=sum(j,i,numArr);                  System.out.print("arrMax["+j+"]["+i+"] = "+arrMax[j][i]+" ");            }            System.out.println();        }        int min = 65525;        int max= 0;        //比较所有从j开始,合并num个数的最小值和最大值        for(int i=0;i<num;i++){            if(min>arr[i][num])                min = arr[i][num];            if(max<arrMax[i][num])                max= arrMax[i][num];        }        bw.write(String.valueOf(min));//写入数据        bw.write("\r\n");//换行        bw.write(String.valueOf(max));//写入数据        bw.flush();//刷新        bw.close();//关闭        br.close();        System.out.println("最小得分是:"+min);        System.out.println("最大得分是:"+max);    }}
0 0
原创粉丝点击