uva 10163 - Storage Keepers 每组最多选一个的分组背包

uva 10163

        有N个仓库,总共有M个人来应聘仓库看守员,每个人的能力是P,一个人可以看守多个仓库(设k个),每个仓库只能被一个人看,仓库的安全系数为p/k,公司的安全底线为最低的仓库安全系数,每个人每月的薪水是P,求能使安全底线最高的值和达到此值中最小的花费。

有两个条件,最低线和花费,要加一维开三维的数组,把每个人看1到n个仓库分作w为p,c为p/k的物品, dp[i][j][k]中i为第i组,总共有j个仓库时,安全线大等于k时的最小花费

#include<stdio.h>
#include<string.h>
#define INF 1<<30
int dp[2][110][1010];
int c[33][110];
int w[33];
int n,m;
int min(int a,int b)
{
    return a>b?b:a;
}
int main()
{
    int i,j,k,l,p,t,pmax;
    while(~scanf("%d %d",&n,&m)&&n+m!=0)
    {
        pmax=-1;
        for(i=0;i<m;i++)
        {
            scanf("%d",&p);
            if(pmax<p)
                pmax=p;
            c[i][0]=0;
            w[i]=p;
            for(j=1;j<=n;j++)
            {
                c[i][j]=p/j;
            }
        }
        for(i=0;i<2;i++)
        {
            for(k=0;k<=pmax;k++)
                dp[i][0][k]=0;
            for(j=1;j<=n;j++)
            {
                for(k=0;k<=pmax;k++)
                    dp[i][j][k]=INF;
            }
        }
        for(i=0;i<m;i++)    //人
        {
            memcpy(dp[i%2],dp[(i+1)%2],sizeof(dp[0]));
            for(j=1;j<=n&&c[i][j];j++)  //当前看几个仓库
            {
                for(t=j;t<=n;t++)  //可以放的状态的仓库数
                {
                   for(k=1;k<=c[i][j];k++)  //可以放的安全系数比它小,不改变当前k值
                    {
                        if(dp[(i+1)%2][t-j][k]!=INF)
                            dp[i%2][t][k]=min(dp[i%2][t][k],dp[(i+1)%2][t-j][k]+w[i]);
                    }
                }
            }
        }
		int flag=0;
        for(i=pmax;i>=0;i--)
        {
            if(dp[(m-1)%2][n][i]!=INF)
            {
                printf("%d %d\n",i,dp[(m-1)%2][n][i]);
				flag=1;
                break;
            }
        }
		if(flag==0)
			printf("0 0\n");
    }
    return 0;
}


你可能感兴趣的:(uva 10163 - Storage Keepers 每组最多选一个的分组背包)