基础算法:
1.回溯法:
1.求问题的解空间
2.如何进行深度优先遍历,是子集树还是排列树(拟合遍历树的结构)
3.如何设计剪枝函数(问题的关键点)
1.n皇后问题:
public static boolean place(int[] arr,int s) {
for (int i = 0; i < s; i++) {
if ((arr[i]==arr[s]) ||(Math.abs(s-i)==(Math.abs(arr[i]-arr[s])))) {
return false;
}
}
return true;
}
public static void trai(int[] arr,int i,int n ) {
if (i>=n) {
++result;
}
else {
for (int j = 1; j<=n; j++) {
arr[i]=j;
if (place(arr, i)) {
trai(arr, i+1, n);
}
}
}
}
2.动态规划:
设计备忘录表的思路是:根据递推(递归)公式来得到的思路
备忘录表中的值:依据是根据递归(递推)公式来得到的
(当我们不知道怎么去建二维备忘录表的横纵坐标时候,我们可以从最优子结构得的递推公式来启发思路)
1.矩阵连乘
package 上机;
//问题:
//1.矩阵如何表示出来
//2.如何打印出来有“()”这种符号
//3.理解递归式子如何来的
//所学:
//1.明白清楚二维矩阵表示的含义;特别是横坐标纵坐标,和合起来是啥
//2.对于遍历的难题,我们思路就是要去思考每一个变量他们之间有哦什么关联,是再不行还可以在这个基础上去带值试试
//3.充分理解二维矩阵对动态规划的作用
//4.明白,当我们不知道怎么去建二维备忘录表的横纵坐标时候,我们可以从最优子结构得的递推公式来启发思路
public class MatrixChain {
// 说明:
// @param p:各个矩阵的下标
// @param m:最优解矩阵
// @param s:最优解矩阵所取得k值的矩阵
// 解释:
// 1.因为规划的表格是一个斜向读取数的表格;
// 因此在取值的时候必须要合理的设计横坐标r,纵坐标i,
// 并且还要设计好j这个变量使他能够斜向的读数据
// 2.m[i][j]表示从第i个矩阵到第j个矩阵间的运算
public static void main(String[] args) {
int []p = {30,35,15,5,10,20,25};
int [][]m = new int [p.length+1][p.length+1];
int [][]s = new int [p.length+1][p.length+1];
System.out.print("最优的结果是:"+ Maxchoose(p,m,s));
System.out.println();
System.out.println("乘法的最优次序:");
traceback(s,1,p.length-1);
}
public static int Maxchoose(int []p,int [][]m,int [][]s){
for(int i=1;i<=p.length;i++){
m[i][i]=0;
}
for(int r = 2; r<= p.length;r++){
for(int i=1;i<=p.length-r;i++){
int j = i+r-1;//难点:!!!!!!!!!
m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k =i+1;k<j;k++){
int t = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t<m[i][j]){
m[i][j] = t;
s[i][j]=k;
}
}
}
}
return m[1][p.length-1];
}
private static void traceback(int[][] s, int i, int j) {
if(i==j)
System.out.print("A"+i);
else if(i+1==j)
System.out.print(" (A"+i+" * "+" A"+j+") ");
else{
System.out.print(" (");
traceback(s,i,s[i][j]);
traceback(s,s[i][j]+1,j);
System.out.print(") ");
}
}
}
3.贪心算法:
1.贪心算法的独特在于在选取,将一个东西从一群中选取出来
2.贪心策略也是有各自的不同,而其中一般有最好的策略
贪心算法基本思想
性质:贪心选择性质和最优子结构性质。
如果一个问题同时具备这两个性质,那么这个问题可以用贪心算法求得整体最优解。
(1)贪心选择性质:指所求问题的最优解可以通过一系列局部最优解来达到。
(2)最优子结构性质:当一个问题的最优解包含其子结构的最优解,称此问题具有最优子结构性质。
基本思想:贪心算法首先设计某种贪心选择策略,第一步做出当前状态的最优选择;然后问题会被演化与原问题相同但是规模更小的子问题;最后用相同的贪心选择策略求解子问题。
哈夫曼编码
package HNode;
import java.util.*;
import org.junit.Test;
/**
* 问题:
* 1.不知道如何用java来建立一个二叉树
* 2.对哈夫曼树的理解不够
* val=0/1是表示自己是左子树还是右子树
* 3.构造哈夫曼树的思路:
* 大体:循环while框架
* 数据体:二叉树类+linkedlist
* 排序(由小到大)---构树--- 将新的树类放回原list中--- 再次循环
*
*
* */
public class Huffman {
//内部类 二叉树节点
private class TreeNode {
public TreeNode() { }
public TreeNode(Character ch, int val, int freq, TreeNode left, TreeNode right) {
this.ch = ch;
this.val = val;
this.freq = freq;
this.left = left;
this.right = right;
}//目的是为了给这个内部类赋值!!!!!!!!!!!!!!!!
Character ch;
int val;
int freq;
TreeNode left;
TreeNode right;
}
@Test
public void testEncode(){
String s = "aaabbbeeedacfwwwwddd";
System.out.println("编码前:"+s);
Object[] encodeRes = encode(s);
String encodeStr = (String)encodeRes[0];
Map<Character,String> encodeMap = (Map<Character, String>)encodeRes[1];
System.out.println("编码表:");
for(Map.Entry<Character,String> e:encodeMap.entrySet()){
System.out.println(e.getKey()+":"+e.getValue());
}
System.out.println("编码后:"+encodeStr);
String decodeStr = decode(encodeStr,encodeMap);
System.out.println("解码后:"+decodeStr);
}
//编码方法,返回Object[],大小为2,Objec[0]为编码后的字符串,Object[1]为编码对应的码表
public Object[] encode(String s){
Object[]res= new Object[2];
//object是所有类的父类,何一个类时候如果没有明确的继承一个父类的话,那么它就是Object的子类;
Map<Character,String> encodeMap = new HashMap<Character, String>();
TreeNode tree = constructTree(s);
findPath(tree, encodeMap, new StringBuilder());
findPath(tree, encodeMap, new StringBuilder());
StringBuilder sb = new StringBuilder();
for(int i=0;i<s.length();i++){
String tmp = encodeMap.get(s.charAt(i));
sb.append(tmp);
}
res[0]=sb.toString();
res[1] = encodeMap;
return res;
}
/*
* 根据字符串建立二叉树
* @param s:要编码的源字符串
*/
private TreeNode constructTree(String s) {
if (s == null || s.equals("")) {
return null;
}
//计算每个字母的词频,放到Map中;
//1.先把s进行分散成char,然后遍历用containsKey方法看是否有,有就放且加一,无则放设置为一
//Character就是char类型类
Map<Character, Integer> dataMap = new HashMap<Character, Integer>();
for (int i = 0; i < s.length(); i++) {
Character c = s.charAt(i);
if (dataMap.containsKey(c)) {
int count = dataMap.get(c);
dataMap.put(c, count + 1);
} else {
dataMap.put(c, 1);
}
}
//遍历dataMap,初始化二叉树节点,并将所有初始化后的节点放到nodeList中,并进行排序
LinkedList<TreeNode> nodeList = new LinkedList<TreeNode>();
for (Map.Entry<Character, Integer> entry : dataMap.entrySet()) {
Character ch = entry.getKey();
int freq = entry.getValue();
int val = 0;
TreeNode tmp = new TreeNode(ch,val,freq,null,null); //1.初始化二叉树节点
nodeList.add(tmp);
}
//对存放节点的链表进行排序,方便后续进行组合
Collections.sort(nodeList, new Comparator<TreeNode>() {
public int compare(TreeNode t1, TreeNode t2) {
return t1.freq-t2.freq; //比较二叉树里面的频率大小,排好序列,放在linkedlist里面
}
});
/*说明:
* 定义:Comparator是外部比较器,用于比较来对象与对象之间的,
* 两个对象进行比较,多用于集合排序,而Comparable可以认为是一个内比较器,
* 根据对象某一属性进行排序的
* */
//size==1,代表字符串只包含一种类型的字母;size 表示nodelist有多少个结点
if(nodeList.size()==1){
TreeNode t = nodeList.get(0);
return new TreeNode(null,0,nodeList.get(0).freq,t,null);
}
//利用排序好的节点建立二叉树,root为初始化根节点
TreeNode root = null;
while(nodeList.size()>0){ //2.开始建立哈夫曼二叉树
//因为nodeList在前面已经排好序,所以直接取出前两个节点,他们的和肯定为最小
TreeNode t1 = nodeList.removeFirst();
TreeNode t2 = nodeList.removeFirst();
//左子树的val赋值为0,右子树的val赋值为1
t1.val = 0;
t2.val = 1;
//将取出的两个节点进行合并
if(nodeList.size()==0){
//此时代表所有节点合并完毕,返回结果
root = new TreeNode(null,0,t1.freq+t2.freq,t1,t2);
}else {
//此时代表还有可以合并的节点
TreeNode tmp = new TreeNode(null,0,t1.freq+t2.freq,t1,t2);
//t1、t2合并后,需要将得到的新节点加入到原链表中,继续与其他节点合并,
//此时需要保证原链表的有序性,需要进行排序
if(tmp.freq>nodeList.getLast().freq){
nodeList.addLast(tmp);
}else {
for(int i=0;i<nodeList.size();i++){
int tmpFreq = tmp.freq;
if(tmpFreq<= nodeList.get(i).freq){
nodeList.add(i,tmp);
//public void add(int index,E element)在此列表中指定的位置插入指定的元素。
//移动当前在该位置处的元素(如果有),所有后续元素都向右移(在其索引中添加 1)。
break;
}
}
}
}
}
//返回建立好的二叉树根节点
return root;
}
//3..对已经建立好的二叉树进行遍历
//对已经建立好的二叉树进行遍历,得到每个字符的编码
private void findPath(TreeNode root, Map<Character,String> res, StringBuilder path) {
if (root.left == null && root.right == null) {
path.append(root.val);
res.put(root.ch,path.substring(1));
path.deleteCharAt(path.length() - 1);
return;
}
path.append(root.val);
if (root.left != null) findPath(root.left, res, path);
if (root.right != null) findPath(root.right, res, path);
path.deleteCharAt(path.length() - 1);
}
/**
* StringBuilder path
* 1.append(int i)
将 int 参数的字符串表示形式追加到此序列。
* 2.deleteCharAt(int index)
移除此序列指定位置上的 char。
* 3.substring(int start)
返回一个新的 String,它包含此字符序列当前所包含字符的子序列。该子字符串始于指定索引处的字符,一直到此字符串末尾。
* 4.length()
返回长度(字符数)。
* */
//对字符串进行解码,解码时需要编码码表
public String decode(String encodeStr,Map<Character,String> encodeMap){
StringBuilder decodeStr = new StringBuilder();
while(encodeStr.length()>0){
for(Map.Entry<Character,String> e: encodeMap.entrySet()){
String charEncodeStr = e.getValue();
if(encodeStr.startsWith(charEncodeStr)){
decodeStr.append(e.getKey());
encodeStr = encodeStr.substring(charEncodeStr.length());
break;
}
}
}
return decodeStr.toString();
}
}
最小生成树
// An highlighted block
/*
* 首先我们给出图的存储结构
*/
package prim;
import java.util.ArrayList;
import java.util.List;
public class zuixiaoTree {
public class Graph {
private List<String> vex;
private int edges[][];
public Graph(List<String> vex, int[][] edges) {
this.vex = vex;
this.edges = edges;
}
public List<String> getVex() {
return vex;
}
public void setVex(List<String> vex) {
this.vex = vex;
}
public int[][] getEdges() {
return edges;
}
public void setEdges(int edges[][]) {
this.edges = edges;
}
public int getVexNum() {
return vex.size();
}
public int getEdgeNum() {
return edges.length;
}
}
int m = Integer.MAX_VALUE;
int[][] edges = {
{0, 3, 1, m, 4},
{3, 0, 2, m, m},
{1, 2, 0, 5, 6},
{m, m, 5, 0, m},
{4, m, 6, m, 0},
};
//打印最小生成树
void MST_Prime(Graph G) {
int vexNum = G.getVexNum();//节点个数
int[] min_weight = new int[vexNum];//当前结果树到所有顶点的最短距离
int[] adjvex = new int[vexNum];//adjvex[C]=0,代表C是通过A加入结果树的(0是A的下标)
/*初始化两个辅助数组*/
for(int i = 0; i < vexNum; i++) {
min_weight[i] = (G.getEdges())[0][i];//第一个顶点到其余顶点的距离
adjvex[i]=0;
}
int min_edg;//当前挑选的最小权值
int min_vex = 0;//最小权值对应的节点下标
/*循环剩余n-1个点*/
for(int i = 1; i < vexNum; i++) {
min_edg = Integer.MAX_VALUE;
for(int j = 1; j < vexNum; j++) {
if(min_weight[j]!=0 && min_weight[j] < min_edg) {
//寻找还没有被挑选进来的,最小权重的点
min_edg = min_weight[j];
min_vex = j;
}
}
min_weight[min_vex] = 0;//纳入结果树
/*修改对应辅助数组的值*/
for(int j = 0; j < vexNum; j++) {
if(min_weight[j]!=0 && (G.getEdges())[min_vex][j]<min_weight[j] && (G.getEdges())[min_vex][j]>0) {
min_weight[j] = (G.getEdges())[min_vex][j];
adjvex[j]=min_vex;
}
}
int pre = adjvex[min_vex];
int end = min_vex;
System.out.println("("+G.getVex().get(pre)+","+G.getVex().get(end)+")");
}
}
//初始化图
Graph init() {
List<String> vex=new ArrayList<String>();
vex.add("A");
vex.add("B");
vex.add("C");
vex.add("D");
vex.add("E");
Graph graph = new Graph(vex, edges);
return graph;
}
public static void main(String[] args) {
zuixiaoTree prime = new zuixiaoTree();
Graph graph = prime.init();
prime.MST_Prime(graph);
}
}
4.分治法
思路:
1.将待求解的较大规模问题分割成k个更小规模的问题
2.对这k个子问题分别求解
3.如果子问题的规模仍然不够小,再划分为k个子问题,如此递归,直到问题规模足够小,可以直接求出解为止
快速排序
package ShuaTi;
public class day3 {
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low];
while (i<j) {
//先看右边,依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
public static void main(String[] args){
int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
归并排序:
public class day2 {
public static void main(String[] args) {
int[] arr = {6, 8, 4, 4, 6, 36, 673, 13, 6, 7, 3, 4, 6, 8, 3, 7, 5, 7, 9, 5};
System.out.print("原数组:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+",");
}
System.out.println();
mergeSort(arr);
System.out.print("合并排序之后的数组:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+",");
}
}
//sort方法的驱动程序
private static void mergeSort(int[] arr) {
sort(arr, 0, arr.length - 1);
}
//将tmp和Cctr当做参数传入,方便调用merge方法时获得这两个参数
private static void sort(int[] arr, int left, int right) {
int mid = (left + right) / 2;
//当分到只剩下一个元素的情况,则退出递归程序
if (left >= right) {
return;
}//这个条件表示下面的步骤就不会进行了(也就是就不会再使用归并排序了)
sort(arr, left, mid);
sort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
private static void merge(int[] arr, int left, int mid, int right) {
//声明三个计时器
int Actr = left;
int Bctr = mid + 1;
int Cctr = 0;
System.out.println(Actr+"aaa"+Bctr);
//创建临时数组,长度为A,B数组长度之和
int[] tmp = new int[right - left + 1];
//循环A,B中长度较短的长度次数的二倍的次数
while (Actr <= mid && Bctr <= right) {
if (arr[Actr] <= arr[Bctr]) {
tmp[Cctr++] = arr[Actr];
Actr++;
} else {
tmp[Cctr++] = arr[Bctr];
Bctr++;
}
}
//如果左边的还有剩余,将左边剩余的合并
while (Actr <= mid){
tmp[Cctr ++] = arr[Actr ++];
}
//如果右边的还有剩余,将右边剩余的合并
while (Bctr <= right){
tmp[Cctr ++] = arr[Bctr ++];
}
//将临时数组更新到原数组
for (int i = 0; i < tmp.length; i++) {
arr[left++] = tmp[i];
}
}
}
5.背包问题整合:
0.1背包问题(使用回溯)
public class Zero_One {
int n = 5;
int capacity = 10;
int[] weight = {2,6,4,1,5};
double[] value = {6,9,6,1,4};
int maxValue = 0;
int tempValue;
int tempWeight;
int[] way = new int[n];
int[] bestWay = new int[n];
public void BackTrack(int t){
//已经搜索到根节点
if(t>n-1){
if(tempValue > maxValue){
maxValue = tempValue;
for(int i=0;i<n;i++)
bestWay[i] = way[i];
}
return;
}
//搜索左边节点
if(tempWeight + weight[t] <= capacity){
tempWeight += weight[t];
tempValue += value[t];
way[t] = 1;
BackTrack(t+1);
tempWeight -= weight[t];
tempValue -= value[t];
way[t] = 0;
}
//不装入这个物品,直接搜索右边的节点
if( Bound(t+1) >= maxValue){
BackTrack(t+1);
}
}
//用于计算剩余物品的最高价值上界
public double Bound(int k){
double maxLeft = tempValue;
int leftWeight = capacity - tempWeight;
//尽力依照单位重量价值次序装剩余的物品
while(k <= n-1 && leftWeight > weight[k] ){
leftWeight -= weight[k];
maxLeft += value[k];
k++;
}
//不能装时,用下一个物品的单位重量价值折算到剩余空间。
if( k <= n-1){
maxLeft += value[k]/weight[k]*leftWeight;
}
return maxLeft;
}
public static void main(String[] args){
Zero_One b = new Zero_One();
b.BackTrack(0);
System.out.println("该背包能够取到的最大价值为:"+b.maxValue);
System.out.println("取出的方法为:");
for(int i : b.bestWay)
System.out.print(i+" ");
}
}
//反思:1.对于算法(问题)的基础需求描述不知道如何解决;
//(就去思考是如何用那种逻辑结构是循环还是遍历)
//2.如何实现遍历回滚、如何剪枝、怎样记录变化量
回溯法的get点:
1.针对问题,定义问题的解空间结构(解的形式)
2.确定易于搜索的解空间结构(是子集树还是二叉树)(将代码与树的遍历拟合)
3.以深度优先方式来搜索解空间,并且确定好剪枝函数(核心发现点)
0.1背包问题(使用分支限定)
package 上机;
/*(同于回溯法的思想)
* 剪枝函数:
* 对于向左搜索,可以通过是否超过背包容量和该节点价值上界能否超过最大值进行剪枝。
* 对于向右搜索,则可以用其父节点的上界减去本层物品的价值,即可得到右边节点的上界。
* */
package BranchAndBounding;
import java.util.*;
//定义节点中的参数以及优先级设置的对象
class thingNode implements Comparable<thingNode>{
int weight;//该节点目前背包中的重量
double value;//该节点目前背包中的总价值
double upprofit;//该节点能够达到的价值上界
int Left; //该节点是否属于左节点(用于最终构造最优解)
int level; //该节点是第几个物品的选择
thingNode father; //该节点的父节点
public int compareTo(thingNode node){
if(this.upprofit<node.upprofit)
return 1;
else if(this.upprofit == node.upprofit)
return 0;
else
return -1;
}
}
public class bag01 {
int n = 5;
int capacity = 10;
int[] weight = {2,6,4,1,5};
double[] value = {6,9,6,1,4};
int maxValue = 0;
int[] bestWay = new int[n];
public void getMaxValue(){
PriorityQueue<thingNode> pq = new PriorityQueue<thingNode>();
//构造一个初始化节点,属于-1层
thingNode initial = new thingNode();
initial.level = -1;
initial.upprofit = 26;
pq.add(initial);
while(!pq.isEmpty()){
thingNode fatherNode = pq.poll();
//当已经搜索到叶子节点时
if(fatherNode.level == n-1){
if(fatherNode.value > maxValue){
maxValue = (int)fatherNode.value;
for(int i=n-1;i>=0;i--){
bestWay[i] = fatherNode.Left;
fatherNode = fatherNode.father;
}
}
}
else{
//先统计其左节点信息,判断是否加入队列。
if(weight[fatherNode.level+1]+fatherNode.weight <= capacity){
thingNode newNode = new thingNode();
newNode.level = fatherNode.level+1;
newNode.value = fatherNode.value + value[fatherNode.level+1];
newNode.weight = weight[fatherNode.level+1]+fatherNode.weight;
newNode.upprofit = Bound(newNode);
newNode.father = fatherNode;
newNode.Left = 1;
if(newNode.upprofit > maxValue)
pq.add(newNode);
}
//向右节点搜索,其能够取到的价值上界通过父亲节点的上界减去本层物品的价值。
if((fatherNode.upprofit - value[fatherNode.level+1])> maxValue){
thingNode newNode2 = new thingNode();
newNode2.level = fatherNode.level+1;
newNode2.value = fatherNode.value;
newNode2.weight = fatherNode.weight;
newNode2.father = fatherNode;
newNode2.upprofit = fatherNode.upprofit - value[fatherNode.level+1];
newNode2.Left = 0;
pq.add(newNode2);
}
}
}
}
//用于计算该节点的最高价值上界
public double Bound(thingNode no){
double maxLeft = no.value;
int leftWeight = capacity - no.weight;
int templevel = no.level;
//尽力依照单位重量价值次序装剩余的物品
while(templevel <= n-1 && leftWeight > weight[templevel] ){
leftWeight -= weight[templevel];
maxLeft += value[templevel];
templevel++;
}
//不能装时,用下一个物品的单位重量价值折算到剩余空间。
if( templevel <= n-1){
maxLeft += value[templevel]/weight[templevel]*leftWeight;
}
return maxLeft;
}
public static void main(String[] args){
bag01 b = new bag01();
b.getMaxValue();
System.out.println("该背包能够取到的最大价值为:"+b.maxValue);
System.out.println("取出的方法为:");
for(int i : b.bestWay)
System.out.print(i+" ");
}
分支界限法与回溯法不同:
1.使用了队列数据结构
2.采用的是广度优先算法遍历
3.对于每一个都有一个最大,最小值作为他的分支判断依据
0.1背包问题(使用动态规划)
package 上机;
//问题:
//1.没有理解到为啥比较上一层
//2.没有注意到数组越界的异常会出现在哪里
// 如:初始化对应的那个值
// 存放的数组和是以1来开始的、而取值的数组是以0开头;
//3.不会将二维数组打印出来
//4.没有深刻的理解到,这样设计是如何实现递归和递推的转化(一步步的计算来的,这样既有递推的步步计算也有递归的思想;)
//5.小心把传入的数组参数与建立的二维数组分开,因为他们的横纵坐标 是不一样的,注意各个值的对应
public class get01PackageAnswer {
public static void main(String[] args) {
int weight[] = {2,3,4,5};
int value[] = {3,4,5,7};
int maxweight = 9;
System.out.println("最后的到的最优的结果是:" + SolvePackage(weight, value, maxweight));
}
public static int SolvePackage(int[] weight,int[] value,int maxweight){
int n=weight.length;
int[][] maxvalue=new int[n+1][maxweight+1];
int[][] chose=new int[n+1][maxweight+1];
for (int i = 0; i <=maxweight; i++) {
maxvalue[0][i]=0;
}
for (int i = 0; i <=n; i++) {//注意取的数组界限
maxvalue[i][0]=0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= maxweight ; j++) {
maxvalue[i][j]=maxvalue[i-1][j];//这里说明:我们默认为初始值是不选自己的
chose[i][j]=0;
if (weight[i-1]<=j) {
if (maxvalue[i-1][j-weight[i-1]]+value[i-1]>maxvalue[i-1][j]) {//因为是>没有等号所以当有相等的情况我们选择没有自己的那个
maxvalue[i][j]=maxvalue[i-1][j-weight[i-1]]+value[i-1];
chose[i][j]=1;
}//*********(重要)***********
}
}
}
//小心区分二维数组和一维数组的初始值,之所以这样设定是为了避免数组越界的异常
System.out.println("各个物品选择的代价:");
for (int[] date : maxvalue) {
for (int result : date) {
System.out.printf("%d\t", result);
}
System.out.println();
}
System.out.println("各个物品选择的情况:");
for (int[] date : chose) {
for (int result : date) {
System.out.printf("%d\t", result);
}
System.out.println();
}
//打印二维数组
return maxvalue[n][maxweight];
}
}