1353: 【提高】机器分配

内存限制:16 MB 时间限制:1.000 S
评测方式:文本比较 命题人:
提交:2 解决:1

题目描述

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

输入

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

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

输出

第一行为一个整数,代表最大盈利的值。

接下来N行,每行两个数,用空格隔开,第一个数代表了第i个公司的序号,第二个数代表该公司分得机器的数量。

样例输入 复制

3 3
30 40 50
20 30 50
20 25 30

样例输出 复制

70
1 1
2 1
3 1

提示

DP 状态定义 dp[i][j]:前i个分公司,一共分配j台机器,能获得的最大盈利。

转移方程

\(dp[i][j]=\max_{0\le k \le j}\big(dp[i-1][j-k] + profit[i][k]\big)\)

  • k:给第i家公司分配k台机器
  • \(j-k\):前\(i-1\)家公司一共分配\(j-k\)台机器
  • \(profit[i][k]\):第i家公司分到k台机器的盈利

初始:dp[0][0]=0,0 个公司 0 台机器盈利为 0。 答案:dp[N][M]。

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 12;
const int MAXM = 20;
int profit[MAXN][MAXM];
int dp[MAXN][MAXM];
int pre[MAXN][MAXM]; // pre[i][j]:前i家共j台,第i家分到k台
int ans[MAXN];       // ans[i]保存第i号公司分到机器数量

int main()
{
    int n, m;
    cin >> n >> m;

    for(int i = 1; i <= n; i++)
    {
        profit[i][0] = 0; // 分配0台,盈利0
        for(int j = 1; j <= m; j++)
        {
            cin >> profit[i][j];
        }
    }

    // dp计算
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            dp[i][j] = 0;
            for(int k = 0; k <= j; k++) // k台分给第i家
            {
                int now = dp[i-1][j - k] + profit[i][k];
                if(now > dp[i][j])
                {
                    dp[i][j] = now;
                    pre[i][j] = k;
                }
            }
        }
    }

    // 回溯,从第n个公司往回推
    int remain = m;
    for(int i = n; i >= 1; i--)
    {
        int k = pre[i][remain];
        ans[i] = k;
        remain -= k;
    }

    //输出
    cout << dp[n][m] << endl;
    for(int i = 1; i <= n; i++)
    {
        cout << i << " " << ans[i] << endl;
    }

    return 0;
}