题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3576
题目大意:某建筑物内有三个电梯,每个电梯最多可承受c人,此建筑物最高位16层,一层的不用乘坐电梯,现在有m人,问怎么样分配这m个人使得三个电梯上升过程中停止的次数最少,要求这m个人必须一次运上去而不能让电梯回来运。
题目思路:这个题就是枚举每一层上的人分配的所有可能然后选择最小停次数就可以。
dp[f][i][j][k]表示到第f层三个电梯人数分别是i、j、k时的最小停次数,用一个hash记录每层需要停的人数
代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=99999999; int dp[18][18][18][18]; int hash[18]; int n,c,m; int min(int a,int b) { return a<b?a:b; } int DP() { memset(dp,-1,sizeof(dp)); dp[1][0][0][0]=0;//第一层没人下 for (int f=2;f<=16;++f)//枚举所有有效层数 { for (int i=0;i<=c;++i) { for (int j=0;j<=c;++j) { for (int k=0;k<=c;++k) { if (dp[f-1][i][j][k]==-1)continue;//第f-1层时i、j、k没处理,只有处理了才回向上扩展第f层 if (i+j+k>m)continue; int res=0; for (int x=0;x<=hash[f];++x)//这里往下是枚举将第f层的人分配到三个电梯中的方案 { for (int y=0;y<=hash[f];++y) { if (x+y>hash[f])continue; int z=hash[f]-x-y; if (i+x>c || j+y>c || k+z>c)continue; res=dp[f-1][i][j][k]+(x>0)+(y>0)+(z>0);//只要x、y、z不为0则需要在这层停一次 if (dp[f][i+x][j+y][z+k]==-1 || dp[f][i+x][j+y][z+k]>res) { dp[f][i+x][j+y][z+k]=res; } } } } } } } int ans=maxn; for (int i=0;i<=c;i++)//枚举进行选择最少停次数 { for (int j=0;j<=c;j++) { if (i+j>m)continue; int k=m-i-j; if (dp[16][i][j][k]==-1)continue; ans=min(ans,dp[16][i][j][k]); } } return ans; } int main() { int t; scanf("%d",&t); for (int cas=1;cas<=t;++cas) { printf("Case %d: ",cas); scanf("%d%d",&c,&m); int a; memset(hash,0,sizeof(hash)); for (int i=1;i<=m;i++) { scanf("%d",&a); hash[a]++; } int ans=DP(); printf("%d\n",ans); } }