前言
继上一篇背包问题–贪心算法,这一次我们来看看动态规划
对于动态规划,一开始看背包问题的时候直接接触的是动态规划
感觉也是比较简单的
题目的具体要求,详细看上一篇,这一篇我们讲述另一个方法
一、动态规划
动态规划需要我们找到最优解,并且可以避免重复的计算,节省时间
动态规划分析
**开始,我们先定义一些声明和变量
Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积
定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值
**
背包问题的动态规划,考虑的是 装和不装的问题,就是01背包问题
所以出现两种情况:
当不装的时候(背包容量比物体的重量小)此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j)
当装入背包,但是可能到达不了最优,也要考虑装和不装
即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}
选取最大值,保证最优
V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减少w(i),但价值增加了v(i)
二、代码实现
1.主布局
相对于上次的贪心算法的布局,这次增加了动态规划
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="背包容量"
android:imeOptions="actionDone"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<!--
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:inputType="number"
android:hint="物品个数"/>
</com.google.android.material.textfield.TextInputLayout>
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_weight="1">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/weight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="物品重量"
android:imeOptions="actionNext"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_weight="1">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/values"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="物品价值"
android:imeOptions="actionNone"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/define"
style="@style/materialButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定"
android:textColor="#CC9933"
app:cornerRadius="12dp"
app:strokeColor="#CC9933"
app:strokeWidth="2dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:layout_marginRight="10dp"
android:text="当前物品个数:"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:id="@+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/greed"
style="@style/materialButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="贪心算法"
android:textColor="#CC9933"
app:cornerRadius="12dp"
app:strokeColor="#CC9933"
app:strokeWidth="2dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/dynamic"
style="@style/materialButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="动态规划"
android:textColor="#CC9933"
app:cornerRadius="12dp"
app:strokeColor="#CC9933"
app:strokeWidth="2dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/goodsRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
这一次我还新增了一个物品的个数的显示,比较方便提醒现在有多少个物品
2.布局
这一个布局呢 是点击了按钮之后跳转活动的布局
这一次动态规划呢 我稍微对布局显示的东西写的复杂了一点
写了两个RecyclerView,不过其实大致是差不多的东西内容
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".page.DynamicProgramming">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:text="背包容量:"
android:textColor="@color/black"
android:textSize="18sp" />
<TextView
android:id="@+id/dynamicBackpack"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:text="" />
</LinearLayout>
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:background="#FFF"
android:text="放入背包的物品为:"
android:textColor="@color/black"
android:textSize="18sp" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/goodDynamic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="5dp"
android:background="#FFF"
android:text=""
android:textColor="@color/black"
android:textSize="18sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dynamic_full"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dynamic_best"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
左边的RecyclerView 我想用来显示全部物品的信息,右边的呢 就是装入背包的物品的信息,就是所谓的最优解
左边:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dynamicFullCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="3dp"
app:cardCornerRadius="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:paddingLeft="10dp"
android:text="物品的重量:" />
<TextView
android:id="@+id/dynamicWeight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text=""
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:paddingLeft="10dp"
android:text="物品的价值:" />
<TextView
android:id="@+id/dynamicValues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text=""
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
右边:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dynamicBestCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="3dp"
app:cardCornerRadius="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginTop="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:paddingLeft="10dp"
android:text="物品的重量:" />
<TextView
android:id="@+id/dynamicWeight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text=""
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:paddingLeft="10dp"
android:text="物品的价值:" />
<TextView
android:id="@+id/dynamicValues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text=""
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:paddingLeft="10dp"
android:lineHeight="20dp"
android:text="第几个放入背包\n(最优解):" />
<TextView
android:id="@+id/dynamicBest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text=""
android:textSize="15sp"
android:layout_marginBottom="10dp"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
3.bean数据
因为我们要找到最优解,那么除了重量和价值之外,还要有一个属性来表示最优解 这里呢我就用best来表示
public class DynamicGood {
private int weight;
private int values;
private int best;
public DynamicGood() {
}
public DynamicGood(int weight, int values) {
this.weight = weight;
this.values = values;
}
public DynamicGood(int weight, int values, int best) {
this.weight = weight;
this.values = values;
this.best = best;
}
//三个属性的get 和 set没有给出
这里 为什么我要写两个构造函数呢?
原因是:因为我们写的两个RecyclerView一个是全部物品,一个是最优解的物品,需要的参数是不一样的!
4.适配器
因为两个只是差一条best的属性,所以其实适配器几乎是一样的
public class DynamicBestAdapter extends RecyclerView.Adapter<DynamicBestAdapter.ViewHolder> {
private Context context;
private List<DynamicGood> list = new ArrayList<>();
public DynamicBestAdapter(List<DynamicGood> list) {
this.list = list;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (context == null) {
context = parent.getContext();
}
//左边使用的cardView不一样
View view = LayoutInflater.from(context).inflate(R.layout.recy_dynamic_best, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
DynamicGood dynamicGoodBest = list.get(position + 1);
holder.dynamicWeight.setText(String.valueOf(dynamicGoodBest.getWeight()));
holder.dynamicValues.setText(String.valueOf(dynamicGoodBest.getValues()));
//左边RecyclerView不用最优解,去掉
holder.dynamicBest.setText(String.valueOf(dynamicGoodBest.getBest()));
}
@Override
public int getItemCount() {
return list.size() - 1;
}
static class ViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView dynamicWeight;
TextView dynamicValues;
//左边RecyclerView 去掉dynamicBest
TextView dynamicBest;
public ViewHolder(@NonNull View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.dynamicBestCard);
dynamicWeight = (TextView) itemView.findViewById(R.id.dynamicWeight);
dynamicValues = (TextView) itemView.findViewById(R.id.dynamicValues);
//左边去掉
dynamicBest = (TextView) itemView.findViewById(R.id.dynamicBest);
}
}
}
这样 两个适配器 我们就写好了 就到我们的Activity了
5.DynamicProgramming Activity
建立模型,即求max(V1X1+V2X2+…+VnXn);
寻找约束条件,W1X1+W2X2+…+WnXn<capacity;
动态规划01背包问题 要保证装入物品的重量小于背包容量,并且价值要最大,有最优解
public class DynamicProgramming extends AppCompatActivity {
private RecyclerView recyclerViewFull, recyclerViewBest;
private DynamicFullAdapter dynamicFullAdapter;
private DynamicBestAdapter dynamicBestAdapter;
private List<DynamicGood> fullList = new ArrayList<>();
private List<DynamicGood> bestList = new ArrayList<>();
private TextView goodDynamic, dynamicBackpack;
private int volume; //背包大小,背包容量
private int bestNumber = 0; //统计有多少个装入背包
private int[][] dynamicProgramming; //动态规划表
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic_programming);
init(); //初始化
programming(); //动态规划
bestSituation(goodsWeight.size() - 1, volume); //最优解情况
print();
}
//打印
private void print() {
dynamicBackpack.setText(String.valueOf(volume));
for (int i = 1; i <= goodsBest.size() - 1; i++) {
if (goodsBest.get(i) == 1) {
bestNumber++; //统计最优解个数
//显示的是最优解的下标
goodDynamic.append(String.valueOf(i));
goodDynamic.append(" ");
}
}
//初始化数组
DynamicGood[] fullDynamic; //全部物品的显示
DynamicGood[] bestDynamic; //装入背包的物品的显示
fullDynamic = new DynamicGood[goodsWeight.size()];
fullDynamic[0] = new DynamicGood(0, 0);
for (int i = 1; i <= goodsWeight.size() - 1; i++) {
fullDynamic[i] = new DynamicGood(goodsWeight.get(i), goodsValues.get(i));
}
fullList.clear();
for (int x = 0; x < fullDynamic.length; x++) {
fullList.add(fullDynamic[x]);
}
bestDynamic = new DynamicGood[goodsBest.size()]; //size 5 所以 bestDynamic.length = 5
int temp = 0; //temp统计最优解的数量 初始化为0 数组第一个边界为0 当best == 1时候 temp++
bestDynamic[temp] = new DynamicGood(0, 0, 0);
for (int i = 1; i <= goodsBest.size() - 1; i++) {
//先遍历 找到装入的物品 goodsBest赋值为1的
//weight values best的下标
if (goodsBest.get(i) == 1) {
bestDynamic[temp += 1] = new DynamicGood(goodsWeight.get(i), goodsValues.get(i), i);
// for (int j = 1; j <= bestNumber; j++) {
// bestDynamic[j] = new DynamicGood(goodsWeight.get(i), goodsValues.get(i), goodsBest.get(i));
// }
}
}
bestList.clear();
for (int x = 0; x <= temp; x++) {
bestList.add(bestDynamic[x]);
}
GridLayoutManager gridLayoutManagerFull = new GridLayoutManager(this, 1);
GridLayoutManager gridLayoutManagerBest = new GridLayoutManager(this, 1);
recyclerViewFull.setLayoutManager(gridLayoutManagerFull);
recyclerViewBest.setLayoutManager(gridLayoutManagerBest);
dynamicFullAdapter = new DynamicFullAdapter(fullList);
dynamicBestAdapter = new DynamicBestAdapter(bestList);
recyclerViewFull.setAdapter(dynamicFullAdapter);
recyclerViewBest.setAdapter(dynamicBestAdapter);
}
//初始化
private void init() {
volume = getIntent().getIntExtra("goodsVolume", 0); //背包容量传值
//volume = getIntent().getDoubleExtra("goodsVolume",0);
dynamicProgramming = new int[goodsWeight.size()][volume + 1]; //动态规划表
goodDynamic = (TextView) findViewById(R.id.goodDynamic);
dynamicBackpack = (TextView) findViewById(R.id.dynamicBackpack);
recyclerViewFull = (RecyclerView) findViewById(R.id.dynamic_full);
recyclerViewBest = (RecyclerView) findViewById(R.id.dynamic_best);
//先保证最优解动态数组全部为0
for (int i = 1; i <= goodsWeight.size() - 1; i++) {
goodsBest.add(0);
}
}
//动态规划
private void programming() {
for (int i = 1; i <= goodsWeight.size() - 1; i++) { //i为第几个物品
for (int j = 1; j <= volume; j++) { //j当前背包容量,相当于背包容量一点一点加,当满足能装入物品时候则开始判断是否装入
if (j < goodsWeight.get(i)) {
//因为容量不够装入物品,所以动态规划表与前一个物品的一样,[前i个物品最佳组合对应的价值][当前背包容量]
//因为不装入物品,所以前i个物品的最佳组合对应的价值相等
dynamicProgramming[i][j] = dynamicProgramming[i - 1][j];
} else {
//当装入物品时候,判断是上一个物品的价值大,还是装入后价值大,求出最优解
dynamicProgramming[i][j] = Math.max(dynamicProgramming[i - 1][j], dynamicProgramming[i - 1][j - goodsWeight.get(i)] + goodsValues.get(i));
}
}
}
}
//找最优解
private void bestSituation(int i, int j) {
if (i - 1 >= 0) {
//传入的参数是最后一个物品的序号i 容量j
if (dynamicProgramming[i][j] == dynamicProgramming[i - 1][j]) { //如果动态规划表中 当前物品和前一个物品的价值相等
// 则表示没有装入物品
goodsBest.set(i, 0); //最优解标记为0 表示没有装入
bestSituation(i - 1, j); //递归再看下一个物品是否是最优解
} else if (j - goodsWeight.get(i) >= 0 && dynamicProgramming[i][j] == dynamicProgramming[i - 1][j - goodsWeight.get(i)] + goodsValues.get(i)) {
//如果背包容量够并且装入后达到最优价值
goodsBest.set(i, 1); //则标记为最优解
bestSituation(i - 1, j - goodsWeight.get(i)); //下一个物品
}
}
}
}
首先就是初始化,这个都是绑定实例,绑定控件的一些代码,还有从Mainactivity将背包容量传过来,这都是跟之前贪心算法一样
然后最优解我也是用动态数组来存储的,之前在贪心算法那篇有说过,动态数组开始的第一个元素为0,为了方便动态规划
在之前的类Goods 中多定义一个动态数组Best
//Goods
//用于动态规划,保存最优解,看哪个物品放入, 最优解情况
public static ArrayList<Integer> goodsBest = new ArrayList<Integer>();
然后进行动态规划programming() 对比是否装入物品,装入物品时候是否是价值最大
然后是找最优解,我们将装入的物品在Best当中标记为1,没装入的物品则是0,等到打印函数print() 也依据Best当中是否为1,来让他显示在我们之前写的右边的RecyclerView当中
最优解,相当于是将动态规划表倒着回去找 从最后一个放入的回头找
如果当前物品和前一个物品价值相等,则没有装入,然后递归下一个
如果背包容量够并且装入后达到最优价值,则为最优解
关于打印部分,也是跟之前一样将对象new出来添加到list里面
不过在最优解的添加到list的部分,因为要考虑是否是最优解,需要判断goodsBest的元素是否等于1,
并且注意,我们返回的是最优解的下标,来以此知道是第几个物品是最优解
6.MainActivity
我们新增加了最优解的数组,也需要开始元素为0
大体上除了点击事件 没有什么变化
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;
private List<Data> dataList = new ArrayList<>();
private TextInputEditText number; //容量
private TextInputEditText weight; //重量
private TextInputEditText values; //价值
private Button define;
private TextView amount; //物品个数(就用int类型)
private int goodsAmount = 0; //物品个数(就用int类型)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 1);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerViewAdapter = new RecyclerViewAdapter(dataList);
recyclerView.setAdapter(recyclerViewAdapter);
}
private void init() {
goodsWeight.add(0);
goodsValues.add(0);
goodsScale.add(0.0); //初始化边界条件,关乎之后数组边界溢出问题
goodsBest.add(0);
Log.d("size","size :"+goodsBest.size());
recyclerView = (RecyclerView) findViewById(R.id.goodsRecycler);
number = (TextInputEditText) findViewById(R.id.number);
weight = (TextInputEditText) findViewById(R.id.weight);
values = (TextInputEditText) findViewById(R.id.values);
amount = (TextView) findViewById(R.id.amount);
define = (Button) findViewById(R.id.define);
define.setOnClickListener(this);
Button greed = (Button) findViewById(R.id.greed);
greed.setOnClickListener(this);
Button dynamic = (Button) findViewById(R.id.dynamic);
dynamic.setOnClickListener(this);
amount.setText(String.valueOf(goodsAmount));
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.define:
//进行判断,保证两个输入框都有值
if (weight.getText() == null || weight.getText().length() == 0 || values.getText() == null || values.getText().length() == 0) {
//未输入完全则提示输入不完全
Toast.makeText(this, "请完整输入物品重量和价值", Toast.LENGTH_SHORT).show();
} else {
int n = Integer.parseInt(weight.getText().toString()); //获取物品重量输入值
int m = Integer.parseInt(values.getText().toString()); //获取物品价值输入值
Data goods = new Data(n, m); //创建Data对象
//dataList.add(goods);
recyclerViewAdapter.add(goods); //加入适配器Adapter 用于显示
goodsWeight.add(n); //将值保存入动态数组
goodsValues.add(m); //将值保存入动态数组
Log.d("111", "...." + goodsWeight.size()); //测试保证动态数组的长度使用
Log.d("111", "......" + goodsWeight.get(1)); //测试保证动态数组的取值使用
weight.setText("");
values.setText(""); //保证每次输入后,输入框的值清空保证下次输入
goodsAmount++;
amount.setText(String.valueOf(goodsAmount));
//保证每次输入后,取消输入框光标
weight.setImeOptions(EditorInfo.IME_ACTION_NONE);
values.setImeOptions(EditorInfo.IME_ACTION_NONE);
}
break;
case R.id.greed:
//判断保证输入背包容量,不至于让计算时候背包容量空值
//在上面已经对两个动态数组进行了边界初始化,所以数组长度已经是1
if (number.getText() == null || number.getText().length() == 0 || goodsWeight.size() == 1 || goodsValues.size() == 1) {
//信息提示
Toast.makeText(this, "请完整输入背包容量或者物品重量和价值", Toast.LENGTH_SHORT).show();
} else {
//到下一个活动求解贪心算法
Intent pageGreed = new Intent(MainActivity.this, PageGreed.class);
//将背包容量传值入贪心算法的活动
int volume = Integer.parseInt(number.getText().toString()); //获取背包容量输入框的值
pageGreed.putExtra("goodsVolume", volume); //Intent对象.putExtra(键值,实际值)
//键值类似指针用于找到值
startActivity(pageGreed);
}
break;
case R.id.dynamic:
if (number.getText() == null || number.getText().length() == 0 || goodsWeight.size() == 1 || goodsValues.size() == 1) {
//信息提示
Toast.makeText(this, "请完整输入背包容量或者物品重量和价值", Toast.LENGTH_SHORT).show();
} else {
Intent dynamicProgramming = new Intent(MainActivity.this, DynamicProgramming.class);
int volume = Integer.parseInt(number.getText().toString());
dynamicProgramming.putExtra("goodsVolume", volume);
startActivity(dynamicProgramming);
}
break;
}
}
}
也是保证了有完整的输入,然后传值
具体难点在于理解,动态规划最优解和动态规划表
因为要求可视化,对于动态规划的打印显示也有一定难点
对于动态规划,其实算法本身不难,我感觉自己写Android代码,对于可视化的要求还是有一点难度的
最后放一张丑丑的运行结果:
总结
目前 背包问题到现在已经有了贪心算法和动态规划
自己在写代码的时候 比较迷糊的也就是关于最优解的问题
还有还有最绕的就是关于RecyclerView的list的添加的问题
因为需要new新的来add到list里面,但是又有限制best需要等于1
PS:这部分写list的时候真的是写着写着头脑迷糊 有点发晕,就很绕
之后还会有蛮力法、贪心算法求解01背包问题近似解等等方法
(具体可以相互学习交流)
来日方长
to be continued……
❤