要求输出选择方案的背包问题,P2066 机器分配

P2066 机器分配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

有一类背包问题,它不仅让你求出最优解,还有求你输出选择方案(选择过程),
下面便是这样一道例题:

题目描述

总公司拥有高效设备 M 台,准备分给下属的 N 个分公司。各分公司若获得这些设备,可以为国家提供一定的盈利。问:如何分配这 M 台设备才能使国家得到的盈利最大?求出最大盈利值。其中 M≤15,N≤10。分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数 M。

输入格式

第一行有两个数,第一个数是分公司数 N,第二个数是设备台数 M。

接下来是一个 N×M 的矩阵,表明了第 i 个公司分配 j 台机器的盈利。

输出格式

第一行为最大盈利值。

接下来 N 行为第 i 分公司分 x 台。

P.S. 要求答案的字典序最小。

输入输出样例

输入 #1复制

3 3
30 40 50
20 30 50
20 25 30

输出 #1复制

70
1 1
2 1
3 1


动态转移的过程就不多讲了,这不是本次的重点,直接看状态转移方程:
f[i][j]=f[i-1][j];
然后
f[i][j]=max(f[i][j],f[i][j-k]+arr[i][k]);

这里的重点是怎么求出方案:
我们可以从后往前找,即从最优解开始往前推
若最优解位置为f[i][j],则他的前一个状态一定满足:
f[i-1][j-k]+arr[k]==f[i][j];
实际上就是价格转移过程的循环逆过来写
本题还需注意一个点:题目要求输出按字典序最小顺序输出
据此,我们能写出如下代码:


#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<math.h>


using namespace std;
typedef long long LL;
const int N = 20;
int arr[N][N], f[N][N],ans[N];
int n, m;

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", &arr[i][j]);
		}
	}

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			f[i][j] = f[i - 1][j];
			for (int k = 0; k <= j; k++) {
				f[i][j] = max(f[i][j], f[i - 1][j - k ] + arr[i][k]);
			}
		}
	}

	/*cout << endl;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cout << f[i][j] << " ";
		}
		cout << endl;
	}*/

	int a = n, b = m;
	while (a) {
		int t = 0;
		for (int k = 0; k <= b;k++) {
			if (f[a][b] - arr[a][k] == f[a - 1][b - k]) {
				ans[a] = k;
				t= b - k;
			}
		}
		a--;
		b = t;
	}

	printf("%d\n", f[n][m]);
	for (int i = 1; i <= n; i++) {
		printf("%d %d\n", i, ans[i]);
	}
	return 0;
}

另一种优化写法(小小的优化)


#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<math.h>



using namespace std;
typedef long long LL;
const int N = 20;
int arr[N][N], f[N][N], ans[N][N];
int n, m;

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", &arr[i][j]);
		}
	}


	for (int i = n; i >= 1; i--) {
		for (int j = m; j >= 1; j--) {
			f[i][j] = f[i + 1][j];
			for (int k = j; k >= 0; k--) {
				if (f[i][j] < f[i + 1][j - k] + arr[i][k]) {
					f[i][j] = f[i + 1][j - k] + arr[i][k];
					ans[i][j] = k;
				}
			}
		}
	}

	printf("%d\n", f[1][m]);
	for (int i = 1,j=m; i <= n; i++) {
		printf("%d %d\n", i, ans[i][j]);
		j -= ans[i][j];
	}
	return 0;
}

posted @ 2023-06-25 21:06  Landnig_on_Mars  阅读(4)  评论(0编辑  收藏  举报  来源