uva 10163 Storage Keepers

题意:有n个仓库(最多100个),m个管理员(最多30个),每个管理员有一个能力值P(接下来的一行有m个数,表示每个管理员的能力值),每个仓库只能由一个管理员看管,但是每个管理员可以看管k个仓库(但是这个仓库分配到的安全值只有p/k,k=0,1,...),每个月公司都要给看管员工资,雇用的管理员的工资即为他们的能力值p和,问,使每个仓库的安全值最高的前提下,使的工资总和最小。输出最大安全值,并且输出最少的花费。

用了两次DP,一次求最大值,一次求最小费用。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define INF 1<<30
const int N=105;
int n,m,imax,data[N],map[N][35];
bool vis[N][35];
int dp1(int,int),dp2(int,int);
void init();
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        init();
        for(int i=1;i<=m;i++) scanf("%d",&data[i]);
        imax=dp1(n,m);
        init();
        if(imax>0) printf("%d %d\n",imax,dp2(n,m));
        else puts("0 0");
    }
    return 0;
}
void init()
{
    memset(map,0,sizeof(map));
    memset(vis,0,sizeof(vis));
}
int dp1(int x,int y)
{
    bool &flag=vis[x][y];
    int &res=map[x][y];
    if(flag) return res;
    else if(x==0||y==0)
    {
        flag=1;
        if(x==0) res=INF;
        else res=0;
        return res;
    }
    else
    {
        res=0;
        for(int i=y;i>0;i--)
        {
            int temp=x>data[i]?data[i]:x;
            for(int j=1;j<=temp;j++)
            {
                res=max(res,min(dp1(x-j,i-1),data[i]/j));
            }
        }
        flag=1;return res;
    }
}
int dp2(int x,int y)
{
    bool &flag=vis[x][y];
    int &res=map[x][y];
    if(flag) return res;
    else if(x==0||y==0)
    {
        flag=1;
        if(0==x) res=0;
        else res=INF;
        return res;
    }
    else
    {
        res=INF;
        for(int i=y;i>0;i--)
        {
            int temp=x>data[i]?data[i]:x;
            for(int j=1;j<=temp;j++)
            {
                if(data[i]/j>=imax)
                res=min(res,dp2(x-j,i-1)+data[i]);
                else break;
            }
        }
        flag=1;return res;
    }
}


你可能感兴趣的:(uva 10163 Storage Keepers)