動態規劃基礎題:機器分配

題目描述

總公司擁有高效設備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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章