Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_36480062
Algorithm
提交
04d0dcc9
A
Algorithm
项目概览
qq_36480062
/
Algorithm
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
Algorithm
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
04d0dcc9
编写于
2月 01, 2020
作者:
qq_36480062
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
commit
上级
284d37fd
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
178 addition
and
19 deletion
+178
-19
algorithm/dp/bag.java
algorithm/dp/bag.java
+128
-19
挑战程序设计竞赛/src/dp/多重部分和.java
挑战程序设计竞赛/src/dp/多重部分和.java
+50
-0
未找到文件。
algorithm/dp/bag.java
浏览文件 @
04d0dcc9
...
...
@@ -8,14 +8,30 @@ import java.util.Arrays;
public
class
bag
{
public
static
void
main
(
String
[]
args
)
{
// System.out.println(dp());
// System.out.println(dpByOne());
System
.
out
.
println
(
dpByWan
());
System
.
out
.
println
(
dpByOne
());
// System.out.println(dpByWan());
// System.out.println(DpbyWanQuanByTwo());
// System.out.println(WanQuanByTWo());
// {//测试价值最高的最小重量,与重量最大的最小价值算法的相同性
// System.out.println(ZeroOneBag(100, 100));
// w = new int[100];
// v = new int[100];
// for (int j = 0; j < 100000; j++) {
// for (int i = 0; i < 100; i++) {
// v[i] = (int) (Math.random() * 100);
// w[i] = (int) (Math.random() * 100);
// }
// if (dpByOne() != ZeroOneBag(100, 100))
// System.out.println("NOOOOOOO");
// }
// }
}
public
static
int
n
=
4
;
//物品数量
public
static
int
W
=
9
;
//背包容量
public
static
int
[]
w
=
{
2
,
2
,
3
,
2
};
//重量
public
static
int
[]
v
=
{
3
,
3
,
4
,
2
};
//价值
public
static
int
[]
w
=
{
2
,
3
,
2
,
4
};
//重量
public
static
int
[]
v
=
{
3
,
2
,
4
,
2
};
//价值
/**
* 01背包问题
...
...
@@ -39,7 +55,7 @@ public class bag {
}
/**
* 非常重要
* 非常重要
,dp[i][j]语义代表,0-i号物品作为可选物品,j作为背包容量,求出的最大价值
*
* @return 总价值最高
*/
...
...
@@ -55,13 +71,13 @@ public class bag {
}
for
(
int
i
=
1
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<=
W
;
j
++)
{
if
(
j
>=
w
[
i
])
{
//要的起
if
(
j
>=
w
[
i
])
{
//
能够选i号物品,
要的起
//选择当前物品,即i号物品,剩余容量。
int
i1
=
v
[
i
]
+
dp
[
i
-
1
][
j
-
w
[
i
]];
int
i2
=
dp
[
i
-
1
][
j
];
dp
[
i
][
j
]
=
Math
.
max
(
i1
,
i2
);
int
i1
=
v
[
i
]
+
dp
[
i
-
1
][
j
-
w
[
i
]];
//选了i号物品的价值
int
i2
=
dp
[
i
-
1
][
j
];
//不选i号物品的价值
dp
[
i
][
j
]
=
Math
.
max
(
i1
,
i2
);
//最后结果取,选或者不选i号物品的最大价值
}
else
{
dp
[
i
][
j
]
=
dp
[
i
-
1
][
j
];
dp
[
i
][
j
]
=
dp
[
i
-
1
][
j
];
//无法选当前i号物品,结果应为不选i号物品的价值
}
}
}
...
...
@@ -71,44 +87,137 @@ public class bag {
return
dp
[
n
-
1
][
W
];
}
/**
* 01背包问题变种,
* 有n个重量和价值分别为wi,vi的物品,从中挑选重量不超过W的物品,
* 求其中可挑选方案中价值总和的最大值
* 限制条件:
* 1≤n≤100
* 1≤wi≤10^7
* 1≤vi≤100
* 1≤W≤10^9
* 其中W重量的范围太大,原来的方法使用O(nW)复杂度太高
* 思路:
* 改变dp的对象,可以使用dp针对不同的价值计算最小的重量
* dp[i][j]代表,可选0-i号物品,在j价值的时候的最小重量
*
* @return 最大价值
*/
public
static
int
ZeroOneBag
(
int
max_v
,
int
max_n
)
{
int
[][]
dp
=
new
int
[
n
+
1
][
max_n
*
max_v
+
1
];
//物品的数量*物品的最大价值=有可能的最大价值,通过这个确定范围
Arrays
.
fill
(
dp
[
0
],
Integer
.
MAX_VALUE
);
dp
[
0
][
0
]
=
0
;
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<=
max_n
*
max_v
;
j
++)
{
if
(
j
<
v
[
i
])
{
dp
[
i
+
1
][
j
]
=
dp
[
i
][
j
];
}
else
{
dp
[
i
+
1
][
j
]
=
Math
.
min
(
dp
[
i
][
j
],
dp
[
i
][
j
-
v
[
i
]]
==
Integer
.
MAX_VALUE
?
dp
[
i
][
j
]
:
dp
[
i
][
j
-
v
[
i
]]
+
w
[
i
]);
//非常重要由于初始化为Integer.MAX_VALUE,再加上重量会溢出为
//dp[i][j - v[i]] + w[i]
}
}
}
int
res
=
0
;
for
(
int
i
=
0
;
i
<=
max_v
*
max_n
;
i
++)
{
if
(
dp
[
n
][
i
]
<=
W
)
res
=
i
;
//最后的i才是价值
}
return
res
;
}
/**
* 一维数组解动态规划
* 每次倒序更新,不然数据不能重用。
* 由于需要的是上次更新的值,正序更新会覆盖上次更新的值,所以只能倒序更新
* 思路:定义一个数组作为辅助空间,初始为n+1,根据dp公式倒序更新
* dp[i][j]语义代表,0-i号物品作为可选物品,j作为背包容量,求出的最大价值
*
* @return 最大价值
*/
public
static
int
dpByOne
()
{
int
[]
dp
=
new
int
[
W
+
1
];
System
.
out
.
println
(
Arrays
.
toString
(
dp
));
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
//控制循环次数
for
(
int
j
=
W
;
j
>=
w
[
i
];
j
--)
{
for
(
int
j
=
W
;
j
>=
w
[
i
];
j
--)
{
//最大背包容量W作为初始值,如果j >= w[i]也就是可以选
dp
[
j
]
=
Math
.
max
(
dp
[
j
],
v
[
i
]
+
dp
[
j
-
w
[
i
]]);
}
System
.
out
.
println
(
Arrays
.
toString
(
dp
));
}
return
dp
[
W
];
}
/**
* 完全背包
*
单个
商品可选多个
* 完全背包
,一维数组解法
*
一种
商品可选多个
*
* @return 最大价值
*/
public
static
int
dpByWan
()
{
int
[]
dp
=
new
int
[
W
+
1
];
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
w
[
i
];
j
<=
W
;
j
++)
{
dp
[
j
]
=
Math
.
max
(
dp
[
j
],
v
[
i
]
+
dp
[
j
-
w
[
i
]]);
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
//选择第i号物品
for
(
int
j
=
w
[
i
];
j
<=
W
;
j
++)
{
//j初始化为第i号物品的重量,非常重要
dp
[
j
]
=
Math
.
max
(
dp
[
j
],
v
[
i
]
+
dp
[
j
-
w
[
i
]]);
//从当前值和dp数组中选出较大值,
//可能会把上次结果覆盖,但符合动态规划策略
}
System
.
out
.
println
(
Arrays
.
toString
(
dp
));
}
return
dp
[
W
];
}
public
static
void
DpbyWan
()
{
/**
* 完全背包问题
* O(nW^2)三层for循环
* 算法复杂度非常高
*
* @return 最大价值
*/
public
static
int
DpbyWanQuanByTwo
()
{
int
[][]
dp
=
new
int
[
n
+
1
][
W
+
1
];
// for (int i = 1; i <= n; i++) {
// for (int j = 0; j <= W; j++) {
// for (int k = 0; k * w[i - 1] <= j; k++) {
// dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * w[i - 1]] + k * v[i - 1]);
// }
// }
// }另一种写法,意思是一样的与下面
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<=
W
;
j
++)
{
for
(
int
k
=
0
;
k
*
w
[
i
]
<=
j
;
k
++)
{
dp
[
i
+
1
][
j
]
=
Math
.
max
(
dp
[
i
+
1
][
j
],
dp
[
i
][
j
-
k
*
w
[
i
]]
+
k
*
v
[
i
]);
}
}
}
for
(
int
i
=
0
;
i
<=
n
;
i
++)
{
System
.
out
.
println
(
Arrays
.
toString
(
dp
[
i
]));
}
return
dp
[
n
][
W
];
}
/**
* 完全背包问题,两层for循环
* O(nW)复杂度
*
* @return 最大价值
*/
public
static
int
WanQuanByTWo
()
{
int
[][]
dp
=
new
int
[
n
+
1
][
W
+
1
];
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<=
W
;
j
++)
{
if
(
j
<
w
[
i
])
{
dp
[
i
+
1
][
j
]
=
dp
[
i
][
j
];
}
else
{
dp
[
i
+
1
][
j
]
=
Math
.
max
(
dp
[
i
][
j
],
dp
[
i
+
1
][
j
-
w
[
i
]]
+
v
[
i
]);
}
}
}
for
(
int
i
=
0
;
i
<=
n
;
i
++)
{
System
.
out
.
println
(
Arrays
.
toString
(
dp
[
i
]));
}
return
dp
[
n
][
W
];
}
}
挑战程序设计竞赛/src/dp/多重部分和.java
浏览文件 @
04d0dcc9
package
dp
;
import
java.util.Arrays
;
/**
* 有n种大小不同的数字ai,每种各有mi个,判断是否可以从这些数字中选出若干个,
* 使他们的和为K
* 示例:
* 输入:
* int n = 3;
* int[] a = {3, 5, 8};
* int[] m = {3, 2, 2};
* int K = 17;
* 输出
* Yes(3*3+8=17)
*/
public
class
多重部分和
{
public
static
void
main
(
String
[]
args
)
{
int
n
=
3
;
int
[]
a
=
{
3
,
5
,
8
};
int
[]
m
=
{
3
,
2
,
2
};
int
K
=
17
;
System
.
out
.
println
(
BuFen
(
n
,
a
,
m
,
K
));
}
public
static
boolean
isBuFen
(
int
n
,
int
[]
a
,
int
[]
m
,
int
K
)
{
boolean
[][]
dp
=
new
boolean
[
n
+
1
][
K
+
1
];
dp
[
0
][
0
]
=
true
;
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<=
K
;
j
++)
{
for
(
int
l
=
0
;
l
<=
m
[
i
]
&&
l
*
a
[
i
]
<=
j
;
l
++)
{
dp
[
i
+
1
][
j
]
|=
dp
[
i
][
j
-
K
*
a
[
i
]];
}
}
}
return
dp
[
n
][
K
];
}
public
static
int
BuFen
(
int
n
,
int
[]
a
,
int
[]
m
,
int
K
)
{
int
[]
dp
=
new
int
[
K
+
1
];
Arrays
.
fill
(
dp
,
1
,
dp
.
length
,
-
1
);
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
j
=
0
;
j
<=
K
;
j
++)
{
if
(
dp
[
j
]
>=
0
)
{
dp
[
j
]
=
m
[
i
];
}
else
if
(
j
<
a
[
i
]
||
dp
[
j
-
a
[
i
]]
<=
0
)
{
dp
[
j
]
=
-
1
;
}
else
{
dp
[
j
]
=
dp
[
j
-
a
[
i
]]
-
1
;
}
}
}
return
dp
[
K
];
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录