POJ 3211 Washing Clothes(01背包)

POJ 3211 Washing Clothes(01背包)

http://poj.org/problem?id=3211

题意:

       有m (1~10)种不同颜色的衣服总共n (1~100)件,Dearboy和她的girlfriend两个人要一起洗完全部衣服,为了预防色彩混合,他们每次只能同时洗同一种颜色的衣服,给出洗完每件衣服所需的时间time和它的颜色color,求出Dearboy和她的girlfriend最少用多少时间能洗完成全部衣服。

分析:

       由于每种颜色的衣服是分开洗的, 所以我们可以把所有衣服按颜色分类, 然后每次看洗一种颜色的衣服最少需要花多少时间即可.

       假设当前第i种颜色的衣服要洗, 由于有两个人, 我们明显让这两个人洗衣服的时间尽量平均才能使得该种衣服洗的时间尽量短.

       那么这就是一个01背包问题了, 选择衣服使得一个人洗衣服的时间在<=sum/2的前提下尽量长.

       对于同一种颜色的衣服有下面01背包过程:

       令dp[i][j]=x表示只在前i件衣服里面选且总时间<=j时, 能达到的最大时间为x.

       初始化: dp全为0.

       状态转移: dp[i][j] = max( dp[i-1][j] , dp[i-1][j-time[i]]+time[i])

       最终所求: 该种衣服所花时间== sum-dp[n][sum/2]. 其中sum为该种衣服所花时间总和.

 

       最终我们把每种衣服花的时间累加起来即可得到ans.

AC代码:

#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;
const int maxn=100000+5;

int n;               //衣服件数
int m;               //颜色种数
int dp[maxn];
int num[10+5];       //num[i]=x表第i类颜色衣服有x个
int val[10+5][100+5];//val[i][j]=x表第i类颜色的第j个衣服需要花x时间洗
map<string,int> mp;  //颜色与编号的映射

int main()
{
    while(scanf("%d%d",&m,&n)==2)
    {
        if(n==0&&m==0) break;
        memset(num,0,sizeof(num));

        //读取输入,存入对应数组
        for(int i=1;i<=m;i++)
        {
            string s;
            cin>>s;
            mp[s]=i;
        }
        for(int i=1;i<=n;i++)
        {
            int x;
            string s;
            cin>>x>>s;
            int type=mp[s];
            val[type][++num[type]]=x;
        }

        //做最多m次01背包
        int ans=0;
        for(int k=1;k<=m;k++)
        {
            //1次01背包
            int sum=0;
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=num[k];i++)
                sum+= val[k][i];
            for(int i=1;i<=num[k];i++)
            {
                for(int j=sum/2;j>=val[k][i];j--)
                    dp[j] = max(dp[j], dp[j-val[k][i]]+val[k][i]);
            }
            //累计结果
            ans+= sum-dp[sum/2];
        }
        printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值