POJ3211Washing Clothes(分组01背包)

题意:两个人洗衣服, 每种颜色的衣服有多件, 要求两人只能同时洗相同颜色的衣服, 求洗衣服的最短时间。

分析:因为只能同时洗相同颜色的衣服, 因此可将不同颜色的衣服看为不同的组, 分别求出来每组的最短时间, 其和即为所求;每组最短时间就是0 1背包;对于每种颜色洗它都有一个总时间,要求洗这种颜色的最少时间,就是求看能不能一个人洗这种颜色的衣服达到总时间的一半,也就是让两个人洗这种颜色的衣服的时间尽可能相同。

解题思路:先求出洗每种颜色的衣服所用的总时间,为了让两个人所用时间尽可能相同,把总时间的一半当做背包容量,每件衣服所花费的时间既是物体体积,又是物品价值,这样就转化为01背包,求背包的最大价值,然后用这种颜色的总时间减去最大价值就是洗这种颜色的衣服所用的最短时间。

注意:dp数组要用滚动数组,不然会超时.

使用vector版本:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<map>
using namespace std;
int dp[2][100005];
int main()
{
    map<string, int> mp;
    vector<int> clo[11];
    int m, n, cnt, time, sum[11], ans, an;
    string tem;
    while(cin >> m >> n)
    {
        if(m == 0 && n == 0)
            break;
        mp.clear();
        for(int i = 0; i <= 10; i++)
            clo[i].clear();
        memset(sum, 0, sizeof(sum));
        ans = cnt = 0;
        for(int i = 0; i < m; i++)
        {
            cin >> tem;
            mp[tem] = ++cnt;
        }
        for(int i = 0; i < n; i++)
        {
            cin >> time >> tem;
            clo[mp[tem]].push_back(time);
            sum[mp[tem]] += time;
        }
        int fi;
        for(int i = 1; i <= cnt; i++)
        {
            fi = 0;
            memset(dp, 0, sizeof(dp));
            int num = clo[i].size();
            int wei = sum[i] / 2;
            for(int j = 0; j < num; j++)
            {
                for(int k = 0; k <= wei; k++)
                {
                    if(k < clo[i][j])
                        dp[!fi][k] = dp[fi][k];
                    else
                        dp[!fi][k] = max(dp[fi][k], dp[fi][k-clo[i][j]] + clo[i][j]);
                }
                fi = !fi;
            }
            //an = max(sum[i] - dp[fi][wei], dp[fi][wei]);
            an = sum[i] - dp[fi][wei];
            ans += an;
        }
        cout << ans << endl;
    }
    return 0;
}


不使用vector版本:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<map>
using namespace std;
int dp[2][100005], clo[11][100];
int main()
{
    map<string, int> mp;
    int m, n, cnt, time, sum[11], ans, an, tol[11];
    string tem;
    while(cin >> m >> n)
    {
        if(m == 0 && n == 0)
            break;
        mp.clear();
        memset(sum, 0, sizeof(sum));
        memset(tol, 0, sizeof(tol));
        ans = cnt = 0;
        for(int i = 0; i < m; i++)
        {
            cin >> tem;
            mp[tem] = ++cnt;
        }
        for(int i = 0; i < n; i++)
        {
            cin >> time >> tem;
            clo[mp[tem]][tol[mp[tem]]++] = time;
            sum[mp[tem]] += time;
        }
        int fi;
        for(int i = 1; i <= cnt; i++)
        {
            fi = 0;
            memset(dp, 0, sizeof(dp));
            int num = tol[i];
            int wei = sum[i] / 2;
            for(int j = 0; j < num; j++)
            {
                for(int k = 0; k <= wei; k++)
                {
                    if(k < clo[i][j])
                        dp[!fi][k] = dp[fi][k];
                    else
                        dp[!fi][k] = max(dp[fi][k], dp[fi][k-clo[i][j]] + clo[i][j]);
                }
                fi = !fi;
            }
            an = max(sum[i] - dp[fi][wei], dp[fi][wei]);
            ans += an;
        }
        cout << ans << endl;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值