UVA-10163 Storage Keepers (DP多次)

Randy Company has N (1 N 100) storages. Company wants some men to keep them safe. Nowthere are M (1 M 30) men asking for the job. Company will choose several from them. RandyCompany employs men following these rules:

  1. Each keeper has a number Pi (1 Pi 1000) , which stands for their ability.

  2. All storages are the same as each other.

  3. A storage can only be lookd after by one keeper. But a keeper can look after several storages. If akeeper’s ability number is Pi, and he looks after K storages, each storage that he looks after hasa safe number Uj = Pi ÷ K.(Note: Uj, Pi and K are all integers). The storage which is lookedafter by nobody will get a number 0.

  4. If all the storages is at least given to a man, company will get a safe line L = min Uj

  5. Every month Randy Company will give each employed keeper a wage according to his abilitynumber. That means, if a keeper’s ability number is Pi, he will get Pi dollars every month. Thetotal money company will pay the keepers every month is Y dollars.

Now Randy Company gives you a list that contains all information about N, M, P, your task is givecompany a best choice of the keepers to make the company pay the least money under the conditionthat the safe line L is the highest.

Input

The input file contains several scenarios. Each of them consists of 2 lines:
The first line consists of two numbers (
N and M), the second line consists of M numbers, meaning

Pi (i = 1..M). There is only one space between two border numbers.The input file is ended with N = 0 and M = 0.

Output

For each scenario, print a line containing two numbers L(max) and Y (min). There should be a spacebetween them.

Sample Input

21
7
12
10 9
25
10 8 6 4 154111100

Sample Output

3710 108 1800 

题意:

给你n个仓库,m个人,第i个人的能力值为pi,每个人可守卫多个仓库,每个仓库只能被一人守卫,若第i个人守护k个仓库,则那些仓库的安全值为pi/k的整数部分,设所有仓库中安全值最低的为t,要求t最大的情况下,消耗最少的能力值。

分析:

第一次dp,求出n个仓库m个人可获得的最大的t。

f[i][j]表示前i个人守护j个仓库的最低安全值,可得f[i][j]=max(f[i][j],min(pi/k,f[i-1][j-k]))

第二次dp,求出在安全值为t的情况下,消耗最少的能力值。

g[i][j]表示前i个人守护j个仓库在安全值最大情况下花费最少的能力值,可得当pi/k>=f[m][n]时,g[i][j]=min(g[i][j],g[i-1][j-k]+pi)

以上k均表示第i个人守护k个仓库时的情况。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const int N=105;
const int mod=1e9+7;

int p[N],f[N][N],g[N][N];

int main() {
    int n,m;
    while (cin>>n>>m&&n) {
        for (int i=1; i<=m; i++) {
            cin>>p[i];
        }
        memset(f, 0, sizeof(f));
        memset(g, INF, sizeof(g));
        for (int i=1; i<=m; i++) {
            f[i-1][0]=INF;
            for (int j=1; j<=n; j++) {
                f[i][j]=f[i-1][j];
                for (int k=1; k<=j; k++) {
                    f[i][j]=max(min(p[i]/k, f[i-1][j-k]),f[i][j]);
                }
            }
        }
        if (f[m][n]==0) {
            g[m][n]=0;
        } else {
            for (int i=1; i<=m; i++) {
                g[i-1][0]=0;
                for (int j=1; j<=n; j++) {
                    g[i][j]=g[i-1][j];
                    for (int k=1; k<=j; k++) {
                        if (p[i]/k>=f[m][n]) {
                            g[i][j]=min(g[i][j], g[i-1][j-k]+p[i]);
                        }
                    }
                }
            }
        }
        
        cout<<f[m][n]<<" "<<g[m][n]<<endl;
    }
    return 0;
}

你可能感兴趣的:(UVA-10163 Storage Keepers (DP多次))