题目链接:http://poj.org/problem?id=3211
题目大意:出题者无比嚣张地show幸福。他们夫妻两洗衣服,衣服有m种颜色,每种颜色又有若干件,每件衣服洗完需要特定的时间,要求每种颜色放在一起洗,洗完才能洗其他衣服。最后问洗完需要的最少时间。
解题思路:由于每种颜色必须分开洗,那我们可以把同一种颜色的分到一个组内,这样分开计算时间再累加起来。那么每组花费的最少时间怎么算呢?如果总和sum,每个人洗sum/2的时间肯定最理想,否则一方少于sum/2,一方多于sum/2,这组的时间久是sum/2,那我们只要找到最接近sum/2的组合结果tpsum,然后与sum-tpsum比较取大者。差不多就是这样,拿生活的事来模拟最有意思了。
状态转移方程:if (dp[k-cost[i][j]]) dp[k] = 1; (i为第i组,j为第i组第j个,k为容量) ,复杂度O(V*sum(num[i]))
测试数据:
3 4
代码:
#include <stdio.h> #include <string.h> #include <map> #include <string> using namespace std; #define MIN 500 #define MAX 110000 #define max(a,b) (a)>(b)?(a):(b) char name[MIN][MIN]; map<string,int> mmap; int m,tot,num[MIN],sum[MIN]; int ans,n,cost[MIN][110],dp[MAX]; int main() { int i,j,k,tpk; char tpstr[MIN]; while (scanf("%d%d",&m,&n), n + m) { mmap.clear(); ans = tot = 0; memset(num,0,sizeof(num)); memset(sum,0,sizeof(sum)); for (i = 1; i <= m; ++i) { scanf("%s",name[i]); mmap[string(name[i])] = ++tot; } for (i = 1; i <= n; ++i) { scanf("%d%s",&tpk,tpstr); k = mmap[string(tpstr)]; sum[k] += tpk; cost[k][++num[k]] = tpk; } for (i = 1; i <= tot; ++i) { memset(dp,0,sizeof(dp)); tpk = sum[i] / 2; for (dp[0] = j = 1; j <= num[i]; ++j) for (k = tpk; k >= cost[i][j]; --k) if (dp[k-cost[i][j]]) dp[k] = 1; while (!dp[tpk]) tpk--; ans += max(tpk,sum[i]-tpk); } printf("%d\n",ans); } }
本文ZeroClock原创,但可以转载,因为我们是兄弟。