题意:有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; } }