一本通 1266:【例9.10】机器分配

【题目描述】

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

【输入】

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

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

【输出】

第一行输出最大盈利值;

接下N行,每行有2个数,即分公司编号和该分公司获得设备台数。

【输入样例】

3 3           //3个分公司分3台机器
30 40 50
20 30 50
20 25 30

【输出样例】

70                                         //最大盈利值为70
1 1                                        //第一分公司分1台
2 1                                        //第二分公司分1台
3 1                                        //第三分公司分1台

【解题思路】

 这个动态转移方程是可以从任意一个枚举的式子中推到出来:

举个例子(就拿求 f[1][2] 的来看):

前面的f数组都是f[0][什么什么],那f[0]总不能就写成这个吧?

那你看,现在的 i 等于几呢?i=1。那应该是f[i-1][什么什么]对吧(i=1,f[0][什么什么],1和0差了1所以是f[i-1][什么什么])。

那是f[i-1][什么呢]?仔细观察会发现应该是f[i-1][k],因为k是在0~j 循环的,j 表示从1~m的设备数量,它的变化规律为:0  1  2…  这些数值恰好都是循环变量 k 的值。

所以是:f[i-1][k]。

到这里,f数组已经搞定。

接下来,我们看v数组:

枚举的式子一直是v[1][什么什么],观察到 i =1,那就是v[i][什么什么]。

那是v[i][什么呢]?

接下来说的就比较难懂了

这里举的例子的 f 数组的 j 的值是从 1~m 的,k 值的范围是从 0(可以有0台机器,看枚举的式子就可以了。如果有0台机器,那f[i][j]的值就为0)~ j.

所以是v[i][j-k]。

最后的动态转移方程为:f[i][j]=max(f[i][j],f[i-1][k]+v[i][j-k]);

这道题的状态转移方程就解决完了,接下来我们来看看程序 接下来还有一个问题,就是要输出:

分公司编号和该分公司获得设备台数 !!!!!

那该怎么办呢?

我们可以用一个标记数组flag,来标记要输出的结果(输出的结果应该是 j - k )。

我们可以用一个输出函数(方便递归输出),print(int x,int y)的函数。

这里就是用来递归输出的,具体看代码。

重点说完了,看代码!!!

【AC代码】

#include <bits/stdc++.h>
#define INF 0X3f3f3f3f
using namespace std;
/*
思路:01背包的变式,
f[i]表示前i个地点开餐馆的最大利润,
状态转移方程:f[i]=max(f[i],f[j]+c[i]);
计算每个位置所能获得的最大利润,再求最大值
*/
int w[1010],c[1010],f[1010],n,k,t;
int main(){
	cin>>t;
	while(t--){
		cin>>n>>k;//输入总数n和距离限制K
		for(int i=1;i<=n;i++){
			cin>>w[i];//输入n个地点位置
		}
		for(int i=1;i<=n;i++){
			cin>>c[i];//输入n个地点的餐馆利润
			f[i]=c[i];//因为可能来的这组数据没有f[i]大,所以不应放在循环外
		}
		//f[1]=c[1];不可以这样写,主要原因看第20行的注释
		for(int i=1;i<=n;i++){
			for(int j=1;j<=i;j++){
				if(w[i]-w[j]>k){//餐馆之间的距离必须 > k
					//f[i]表示前i个地点开餐馆的最大利润
					f[i]=max(f[i],f[j]+c[i]);
				}
			}
		}
		int maxx=-INF;//初值无限小,好比较
		for(int i=1;i<=n;i++){//再求利润最大值
			maxx=max(f[i],maxx);
		}
		cout<<maxx<<endl;
	}
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值