/*
题意:两个人洗衣服, 每种颜色的衣服有多件, 要求两人只能同时洗相同颜色的衣服,
求洗衣服的最短时间。
分析:因为只能同时洗相同颜色的衣服, 因此可将不同颜色的衣服看为不同的组,
分别求出来每组的最短时间, 其和即为所求;每组最短时间就是0 1背包;
对于每种颜色洗它都有一个总时间,要求洗这种颜色的最少时间,
就是求看能不能一个人洗这种颜色的衣服达到总时间的一半,
也就是让两个人洗这种颜色的衣服的时间尽可能相同。
解题思路:先求出洗每种颜色的衣服所用的总时间,为了让两个人所用时间尽可能相同,
把总时间的一半当做背包容量,每件衣服所花费的时间既是物体体积,
又是物品价值,这样就转化为01背包,求背包的最大价值,
然后用这种颜色的总时间减去最大价值就是洗这种颜色的衣服所用的最短时间。
*/
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=105;
struct Node
{
int t;//洗这件衣服的时间
int c;//这件衣服的颜色
};
char temp[15][15];//保存颜色的数组
int dp[100005];//背包
int C_time[15];//每种颜色衣服要洗所花费的总时间
Node clothe[MAXN];//结构体:每件衣服
int myfind(char s[],int m)//寻找当前这件衣服的颜色是哪一种。(根据开始输入颜色的顺序分别为
{ //1到m。(将颜色数字化)
for(int i=1;i<=m;i++)
{
if(strcmp(s,temp[i])==0)
{
return i;
}
}
}
int mymax(int a,int b)
{
return a>b?a:b;
}
int main()
{
int n,m;
while(cin>>m>>n)
{
if(!m&&!n)
{
break;
}
int sum=0;
memset(C_time,0,sizeof(C_time));
for(int i=1;i<=m;i++)
{
cin>>temp[i];
}
for(int i=1;i<=n;i++)
{
char s[15];
cin>>clothe[i].t;//洗这件衣服要花费的时间
cin>>s;//这件衣服的颜色
clothe[i].c=myfind(s,m);//颜色数字化
C_time[clothe[i].c]+=clothe[i].t;//这种颜色的衣服要花费的总时间
}
for(int i=1;i<=m;i++)
{
memset(dp,0,sizeof(dp));
int ans=C_time[i]/2;//给你洗这种颜色衣服的总时间一半的背包。
for(int j=1;j<=n;j++)//01背包
{
if(clothe[j].c==i)//判断是否是同一个颜色的衣服
{
for(int k=ans;k>=clothe[j].t;k--)//01背包,选择洗还是不洗。
{
dp[k]=mymax(dp[k],dp[k-clothe[j].t]+clothe[j].t);
}
}
}//这种颜色的总时间减去最大价值就是洗这种颜色的衣服所用的最短时间
sum+=(C_time[i]-dp[ans]);
}
cout<<sum<<endl;
}
return 0;
}
刚开始用了一种模拟的方法,感觉思路没问题,但是不能AC,想不明白。
也把代码放上来吧。
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN=110;
struct Node
{
int t;//时间
int c;//颜色(数字化)
};
int n,m;
char temp[20][20];//颜色数组
int num[20];//num[i]:第i种颜色出现的次数
int dpm[20],dpg[20];//dpm[i]:男的洗颜色为i的衣服所需的时间。dpg[i]:女的洗颜色为i的衣服所需的时间
bool cmp(Node a,Node b)//按颜色排序(当颜色相同时,按时间递增排序)
{
if(a.c==b.c)
{
return a.t<b.t;
}
else
{
return a.c<b.c;
}
}
int myfind(char s[],char temp[][15]) //颜色数字化
{
for(int i=1;i<=m;i++)
{
if(strcmp(s,temp[i])==0)
{
return i;
}
}
return 0;
}
int mymax(int a,int b)
{
return a>b?a:b;
}
int main()
{
while(cin>>m>>n)
{
if(!m&&!n)
{
break;
}
Node Clothes[MAXN];
memset(dpm,0,sizeof(dpm));
memset(dpg,0,sizeof(dpg));
memset(num,0,sizeof(num));
for(int i=1;i<=m;i++)
{
cin>>temp[i];
}
int sum=0,j=0;
for(int i=1;i<=n;i++)
{
char s[12];
cin>>Clothes[i].t;
cin>>s;
Clothes[i].c=myfind(s);//颜色数字化
num[Clothes[i].c]++;//这种颜色出现的次数+1
}
sort(Clothes+1,Clothes+n+1,cmp); //按颜色和时间排序
for(int i=1;i<=m;i++)
{
int k=0;//控制每一种颜色的数量
for(j=j+num[i];k<num[i];k++,j--)//逆序选择衣服(因为同种颜色的衣服
{ //越往后面时间越大)
if(dpm[i]+Clothes[j].t<=dpg[i]+Clothes[j].t)//如果男的选择洗这件衣服比女的洗
{ //这件衣服要的总时间要小,则男的洗
dpm[i]+=Clothes[j].t;
}
else//否则女的洗
{
dpg[i]+=Clothes[j].t;
}
}
j+=k;
sum+= mymax(dpm[i],dpg[i]);//这种颜色的衣服的最大值就是洗这种颜色衣服要花的最小时间。
} //因为dpm,dpg是尽可能的将总时间平均分为2份的。
cout<<sum<<endl;
}
return 0;
}