01.题目及链接
题目链接:https://www.luogu.com.cn/problem/P5322
02.分组背包说明
分组背包:有k组物品,N个物品,一个容量是C的背包。每组物品有若干个,同一组内的物品最多只能选一个。
状态转移方程
定义状态: dp[k][j] 最大承重为j,有前k组物品可选时的最大价值
for (int k = 1; k <= groupNum; k++) {// 所属组k
for (int j = 0; j <= capacity; j++) {// 容量j
for (int i = 0; i < I; i++) {// 所属分组k的物品I
dp[k][j]=Math.max(dp[k - 1][j],
dp[k - 1][j - 物品i的重量] + 物品i的价值);
}
}
}
状态转移方程压缩
定义状态:dp[j] 最大容量为j的前提下,物品的最大价值
for (int k = 1; k <= groupNum; k++) {// 所属组k
for (int j = capacity; j >= 0; j--) {// 容量j
for (int i = 0; i < I; i++) {// 所属分组k的物品I
dp[j]=Math.max(dp[j], dp[j-data[i][0]]+data[i][1]);
}
}
}
03.解题思路
题意分析:小 C 通过某些途径得知了其他 s 名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分==>小C的调兵策略只有一个,不能动态改变调兵策略
算法执行流程
- 分别对按座城堡对每一个玩家派去的士兵数量升序排序
- 状态定义:分组的组是城堡的个数(假设为k),定义状态dp[i]:表示士兵人数为i时小 C 总分的最大值
- 状态转移:
dp[j]=Math.max(dp[j], dp[j-2*(第i个人派去第k座城堡的数量)-1]+k*i);
04.具体代码
public static void main(String[] args) throws IOException {
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String[] tmps=in.readLine().split(" ");
// s名玩家 n座城堡(组) 玩家有 m名士兵(容量)
int s=Integer.valueOf(tmps[0]),n=Integer.valueOf(tmps[1]),m=Integer.valueOf(tmps[2]);
int[][] data=new int[s+1][n+1];
for (int i = 1; i <= s; i++) {
tmps=in.readLine().split(" ");
for (int j = 1; j <= n; j++) {
data[i][j]=Integer.valueOf(tmps[j-1]);
}
}
//数组按列进行排序(从小到大排序)
for (int j = 1; j <= n; j++) {
int[] tmp=new int[s+1];
for (int i = 1; i <= s; i++) {
tmp[i]=data[i][j];
}
Arrays.sort(tmp);
for (int i = 1; i <= s; i++) {
data[i][j]=tmp[i];
}
}
int[] dp=new int[m+1];
for (int k = 1; k <= n; k++) {
for (int j = m; j >= 1; j--) {
for (int i = 1; i <= s; i++) {
if(j>=2*data[i][k]+1) dp[j]=Math.max(dp[j], dp[j-2*data[i][k]-1]+k*i);
}
}
}
System.out.println(dp[m]);
in.close();
}
05.更多背包学习
https://blog.csdn.net/qq_46237746/article/details/123908504