【题目描述】
总公司拥有高效设备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;
}