洛谷P2066 机器分配【dp】

洛谷P2066 机器分配【dp】

题目链接:https://www.luogu.com.cn/problem/P2066

题目描述

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

输入格式

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

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

输出格式

第1行为最大盈利值

第2到第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

先不考虑字典序最小的问题,代码很好写。就是个背包

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e3;
int n,a[maxn][maxn],f[maxn][maxn],ans[maxn][maxn];
void print(int n, int m){//用于输出前n个公司,分配m台机器的方案
	if(n == 0) return;
	else{
		print(n-1, m-ans[n][m]);//往前递归
		printf("%d %d
", n, ans[n][m]);//输出公司编号和设备数
	}
}
int main(){
    int n,m; scanf("%d%d",&n, &m);
    for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)scanf("%d", &a[i][j]);//第i个公司分配j台机器的盈利。 
    for(int i=1; i<=n; i++)//公司
      	for(int j=1; j<=m; j++)//总共分配的机器数
     		for(int k=0; k<=j; k++)//给当前公司分配几个设备
				if(f[i][j]<=f[i-1][j-k]+a[i][k]){
					f[i][j] = f[i-1][j-k]+a[i][k];
					ans[i][j] = k;//记录一下方案,前i个公司分配j台机器时,公司i获得的设备数
				}
	printf("%d
", f[n][m]);
	print(n,m);
    return 0;
}

看这组数据:

2 15
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 2

刚才的程序输出:

2
1 1
2 1

但字典序最小的方案是:

2
1 0
2 15

若考虑上字典序呢,我们就让编号靠后的公司分配的机器多一点,这样前面分配的机器就少,字典序就小

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e3;
int n,a[maxn][maxn],f[maxn][maxn],ans[maxn][maxn];
void print(int n, int m){
	if(n == 0) return;
	else{
		print(n-1, m-ans[n][m]);
		printf("%d %d
", n, ans[n][m]);
	}
}
int main(){
    int n,m; scanf("%d%d",&n, &m);
    for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d", &a[i][j]);
    for(int i=1; i<=n; i++)
      	for(int j=1; j<=m; j++)
     		for(int k=0; k<=j; k++)
				if(f[i][j]<=f[i-1][j-k]+a[i][k]){//只有这不同,小于等于
					f[i][j] = f[i-1][j-k]+a[i][k];
					ans[i][j] = k;
				}      	
	printf("%d
", f[n][m]);
	print(n,m);
    return 0;
}

为什么改成小于等于就对了?如果我们在等于时也更新一下ansi j= k;

就可以保证这个k是最优状态里最大的,也就保证最终得到的方案字典序最小

还有一种写法,就是倒序枚举i,j,k,这样一开始记录的k值就是最大的

原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12769739.html