題目描述
總公司擁有高效設備M臺,準備分給下屬的N個分公司。各分公司若獲得這些設備,可以爲國家提供一定的盈利。問:如何分配這M臺設備才能使國家得到的盈利最大?求出最大盈利值。其中M≤15,N≤10。分配原則:每個公司有權獲得任意數目的設備,但總檯數不超過設備數M。
輸入輸出格式
輸入格式:
第一行有兩個數,第一個數是分公司數N,第二個數是設備臺數M。
接下來是一個N*M的矩陣,表明了第 I個公司分配 J臺機器的盈利。
輸出格式:
第1行爲最大盈利值
第2到第n爲第i分公司分x臺
我們分析,對於分配給前i個公司j臺機器的價值,實際上相當於前i-1個公司分配k臺機器並給第i個公司分配j-k臺機器的價值總和。由此,這種最優子結構自然讓我們能列出如下的轉移方程:
令f[i][j]表示分配給前i個公司j臺機器的價值,則有
f[i][j]=f[i-1][k]+v[i][j-k]
其中,k從0~j循環,取出最大值即可。
我們很容易寫出轉移過程的代碼:
f[i][j]=max(f[i][j],f[i-1][k]+v[i][j-k]);
那麼,如何將轉移的過程記錄下來呢?我們可以在計算完成後,採用倒推的思想。採用遞歸實現的具體過程如下:
void print_link(int i,int j)
{
if(!i) return;
for(int k=j;k>=0;--k)
if(f[i][j]==f[i-1][j-k]+v[i][k]){
print_link(i-1,j-k);
printf("%d %d\n",i,k);break;}
return;
}
核心部分已經完成,我們來撰寫剩餘的代碼:
#include <cstdio>
#include <cstring>
#define reset(x) memset(x,0,sizeof(x))
#define max(x,y) (x>y?x:y)
using namespace std;
int v[20][20],f[20][20];
void print_link(int i,int j)
{
if(!i) return;
for(int k=j;k>=0;--k)
if(f[i][j]==f[i-1][j-k]+v[i][k]){
print_link(i-1,j-k);
printf("%d %d\n",i,k);break;}
return;
}
int main()
{
int i,j,k,n,m,t;
reset(v);reset(f);
scanf("%d%d",&n,&m);
for(i=1,j=1;i<=n;i+=(j==m),j=j==m?1:j+1) scanf("%d",&v[i][j]);
for(i=1,j=0;i<=n;i+=(j==m),j=j==m?1:j+1)
for(k=0;k<=j;k++) f[i][j]=max(f[i][j],f[i-1][j-k]+v[i][k]);
printf("%d\n",f[n][m]);
print_link(n,m);
return 0;
}