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 ",ans); } return 0; }