【題解】機器分配(DP)

題面

【題目描述】
總公司擁有高設備MM臺,準備分給下屬的NN個分公司。各分公司獲得這些設備,可以爲國家提供一定的盈利。問:如何分配這MM臺設備才能使國家得到的盈利最大?求出最大盈利值。其中M15,N10M\leq 15,N\leq 10。分配原則:每個公司有權獲得任意數目的設備,但總檯數不超過設備數MM
【輸入】
11行有兩個數,第11個數是分公司數NN,第22個數是總設備臺數MM。接下來是NMN*M的矩陣,表明了第II個公司分配JJ臺機器的盈利。
【輸出】
11行輸出最大盈利值,接下來NN行,每行22個數,即分公司編號和該公司獲得設備臺數。
【樣例輸入】

3 3
30 40 50
20 30 50
20 25 30

【樣例輸出】

70
1 1
2 1
3 1

算法分析

DPDP
狀態:
dp[i][j]dp[i][j]——前ii個公司分jj臺設備的最大盈利。

狀態轉移方程:
如果前i1i-1個公司已經分配完了,考慮第ii個公司分配的機器數量,設分得kk臺,kk可能爲00~jj,那麼前i1i-1個公司只能分配jkj-k臺。
a[x][y]a[x][y]表示第xx個公司分配yy臺設備的盈利。
因此,只需要考慮第ii個公司分配了多少臺機器:

dp[i][j]=maxdp[i][j]=max{ dp[i][j],dp[i1][jk]+a[i][k]dp[i][j],dp[i-1][j-k] +a[i][k] },0kj0\leq k \leq j。

邊界:
dp[i][0]=0dp[i][0]=0ii個公司分配00臺設備盈利爲00.
dp[0][j]=0dp[0][j]=000個公司分配jj臺設備盈利爲00

輸出方案
最後的答案爲dp[n][m]dp[n][m],即nn個公司分mm臺設備的最優解。
通過狀態轉移方程可以知道,dp[n][m]dp[n][m]是由dp[n1][jkn]+a[n][kn]dp[n-1][j-k_n]+a[n][k_n]得到的,即前n1n-1個公司分mknm-k_n臺設備,第nn個公司分配knk_n臺設備。數組aa是已知的,dpdp數組也是已知的,而knk_n是未知的,因此,可以枚舉knk_n,檢驗knk_n在何時滿足dp[n][m]dp[n][m],則找到了第nn個公司分配到的設備數。
同理,繼續找dp[n2][mknkn1]+a[n1][kn1]dp[n-2][m-k_n-k_{n-1}]+a[n-1][k_{n-1}],檢驗第n1n-1個公司分配的設備數…
採用遞歸來實現。

參考程序

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[200][200],dp[200][200],num[200],mx,s[200],ans=0;
void print(int i,int j)	//遞歸尋找答案,前i個公司分j臺 
{
	if(ans) return;		//找到答案不再找了 
    if(i==0) 
    {
    	int tmp=0;
    	for(int k=1;k<=n;k++)
    		tmp+=s[k];
    	if(tmp==m)			//m臺設備全部分完 
    	{
    		for(int k=1;k<=n;k++)
    			cout<<k<<' '<<s[k]<<endl;	
			ans=1; 
		}
		return;
	}
    for(int k=0;k<=j;k++)	//前i-1個公司分j-k臺,第i個公司分k臺
    {
        if(dp[i][j]==dp[i-1][j-k]+a[i][k])
        {
			s[i]=k;				//記錄 
            print(i-1,j-k);
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    for(int i=1;i<=n;i++)
    {
         
        for(int j=1;j<=m;j++)
        {
            mx=0;
            for(int k=0;k<=j;k++)	//考慮第i個公司分配了k臺設備 
            {
                if(dp[i-1][j-k]+a[i][k]>mx)			//取最優解 
                    mx=(dp[i-1][j-k]+a[i][k]);
            }
            dp[i][j]=mx;	
        }
    }
    cout<<dp[n][m]<<endl;
    print(n,m);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章