题目链接: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
red blue yellow
2 red
3 blue
4 blue
6 red
3 4
red blue yellow
3 red
3 red
4 blue
4 blue
代码:
#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原创,但可以转载,因为我们是兄弟。