题目链接:
https://www.acwing.com/problem/content/description/1015/
#分组背包 #记录路径
思路
泛化物品的题,每个公司都是一个泛化物品,给定一个体积,能得到一个价值
泛化物品的和,针对一个特定的体积,就是枚举两个物品体积的分配方案,取最优解
整个过程就相当于是分组背包的过程
把每个公司想成一个组,每个组里面只能选一种方案
最后输出时麻烦了一点,但思路和 [[LG P1759 通天之潜水]] 一样
pop[i][j]=k
代表前 i 组物品中,体积为 j 时,选了该组中的第 k 个
所以就可以倒推:
pop[i][j]
如果不为 0,代表从第i组中选了某个物品,即选了该组中编号为pop[i][j]
的物品,所以递归到 `print(i-1,m-w[group[i][j]])pop[i][j]
如果为 0,说明没有从第i组选物品,直接递归到print(i-1,j)
- 注意边界处理,递归到
i==1
时记得return
代码
import java.io.*;
import java.util.*;
import static java.lang.Math.*;
public class Main {
static int status;
static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static PrintWriter cout = new PrintWriter(bw);
static StreamTokenizer st = new StreamTokenizer(buf);
public static int nextInt() throws IOException {
status = st.nextToken();
return (int) st.nval;
}
static final int INF = Integer.MAX_VALUE-666666;
static int n,m;
static int[][] pop, a;
static int[] f, way;
public static void main(String[] args) throws IOException {
n = nextInt();
m = nextInt();
a = new int[n+1][m+1];
pop = new int[n + 1][m + 1];
way = new int[n+1];
f = new int[m + 1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j] = nextInt();
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
for(int k=1;k<=m;k++)
if(j - k >= 0){
if(f[j-k] + a[i][k] > f[j]){
f[j] = f[j-k] + a[i][k];
pop[i][j] = k;
}
}
cout.println(f[m]);
print(n, m);
for(int i=1;i<=n;i++){
cout.println(i + " " + way[i]);
}
cout.flush();
}
public static void print(int i,int j){
if(i == 1){
if(pop[i][j] > 0)
way[i] = pop[i][j];
return;
}
if(pop[i][j] > 0){
print(i-1, j - pop[i][j]);
way[i] = pop[i][j];
}else{
print(i-1, j);
}
}
}