军训第三天 继续背包....
这道题最难的地方不是二维费用的处理,我觉得反而是 人数和时间优先级的判断反而是这道题的难点。 不过仔细想想也是能有思路的:先进行二维费用的判断 如果选择当前妹子 比不选这个妹子 能泡到的妹子更多的话 这个妹子必泡不可了(这是我编程以来说过最正经的话。)如果 选择当前妹子和不选这个妹子 泡到的妹子一样多的话.那就比较时间 选择时间小的进行累加。
题目描述金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
先完成的是昨天二维费用的题目 40分的找啊找啊找GF....
LUOGU1509 找啊找啊找GF
题目背景"找啊找啊找GF,找到一个好GF,吃顿饭啊拉拉手,你是我的好GF.再见.""诶,别再见啊..."七夕...七夕...七夕这个日子,对于sqybi这种单身的菜鸟来说是多么的痛苦...虽然他听着这首叫做"找啊找啊找GF"的歌,他还是很痛苦.为了避免这种痛苦,sqybi决定要给自己找点事情干.他去找到了七夕模拟赛的负责人zmc MM,让她给自己一个出题的任务.经过几天的死缠烂打,zmc MM终于同意了.但是,拿到这个任务的sqybi发现,原来出题比单身更让人感到无聊-_-....所以,他决定了,要在出题的同时去办另一件能够使自己不无聊的事情--给自己找GF.sqybi现在看中了n个MM,我们不妨把她们编号1到n.请MM吃饭是要花钱的,我们假设请i号MM吃饭要花rmb[i]块大洋.而希望骗MM当自己GF是要费人品的,我们假设请第i号MM吃饭试图让她当自己GF的行为(不妨称作泡该MM)要耗费rp[i]的人品.而对于每一个MM来说,sqybi都有一个对应的搞定她的时间,对于第i个MM来说叫做time[i]. sqybi保证自己有足够的魅力用time[i]的时间搞定第i个MM^_^.sqybi希望搞到尽量多的MM当自己的GF,这点是毋庸置疑的.但他不希望为此花费太多的时间(毕竟七夕赛的题目还没出),所以他希望在保证搞到MM数量最多的情况下花费的总时间最少.
看到这题目我很想说:出模拟题去 找什么GF??? 吐槽归吐槽 然而还是得把这道题打出来 ..
#include<bits/stdc++.h>
using namespace std;
struct choose
{
int num,time;
}f[200][200];
struct meizi
{
int money,rp,time;
}me[200];
int main()
{
int n,m,r,t;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&me[i].money,&me[i].rp,&me[i].time);
scanf("%d%d",&m,&r);
for(int i=1;i<=m;i++)
for(int j=1;j<=r;j++)
{f[i][j].num=0;f[i][j].time=0;}
for(int i=1;i<=n;i++)
for(int j=m;j>=me[i].money;j--)
for(int k=r;k>=me[i].rp;k--)
if((f[j-me[i].money][k-me[i].rp].num+1>f[j][k].num)||((f[j-me[i].money][k-me[i].rp].num+1==f[j][k].num)&&(f[j-me[i].money][k-me[i].rp].time+me[i].time<f[j][k].time)))
{
f[j][k].num=f[j-me[i].money][k-me[i].rp].num+1;
f[j][k].time=f[j-me[i].money][k-me[i].rp].time+me[i].time;
}
cout<<f[m][r].time;
}
这是最终的代码
这道题最难的地方不是二维费用的处理,我觉得反而是 人数和时间优先级的判断反而是这道题的难点。 不过仔细想想也是能有思路的:先进行二维费用的判断 如果选择当前妹子 比不选这个妹子 能泡到的妹子更多的话 这个妹子必泡不可了(这是我编程以来说过最正经的话。)如果 选择当前妹子和不选这个妹子 泡到的妹子一样多的话.那就比较时间 选择时间小的进行累加。
搞定了二维费用的题目 就是分组背包了 分组背包每组只能选一个物品.那么就要多一重循环了 一个需要理解的点就是 :容量的循环在外面 组中物品的循环在里面 是为了每组的物品只选一个。
LUOGU1757 通天之分组背包
题目描述自01背包问世之后,小A对此深感兴趣。一天,小A去远游,却发现他的背包不同于01背包,他的物品大致可分为k组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。
分组背包的一个题目.AC代码如下: #include<bits/stdc++.h>
using namespace std;
int f[2000]={0},a[200]={0};
struct things
{
int weight,value,group;
}th[2000];
bool mycup(things a,things b)
{return a.group<b.group;}
int main()
{
int m,n,s;
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&th[i].weight,&th[i].value,&th[i].group);
sort(th+1,th+1+n,mycup);
s=1;
for(int i=1;i<=n;i++)
if(th[i].group!=s) s=th[i].group;
for(int i=1;i<=s;i++)
{
for(int j=m;j>=1;j--)
for(int k=1;k<=n;k++)
if (th[k].group==i)
{
if (j>=th[k].weight) f[j]=max(f[j],f[j-th[k].weight]+th[k].value);
}
}
printf("%d",f[m]);
}
呃...这个题目也过得非常艰难.....一开始我循环的代码是这样的:
for(int i=1;i<=n;i++)
if(th[i].group==s) a[i]=s;
else {s=th[i].group;a[i]=s;}
int t1=1,t2=1;
for(int i=1;i<=s;i++)
{
t1=t2;
for(int j=m;j>=1;j--)
for(int k=t1;k<=n;k++)
if (a[k]==i)
{
if (j>th[k].weight) f[j]=max(f[j],f[j-th[k].weight]+th[k].value);
if(j==m)t2++;
}
else break;
}
一个问题就是a数组很累赘 并没有什么用的a数组然后t2 和t1 和break的处理有很大的问题.....
然后就学有依赖的背包问题..例题如下:
LUOGU1064 金明的预算方案
题目描述金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*为乘号)请你帮助金明设计一个满足要求的购物单。z
因为这题的附件最多为2个 导致这题有两个办法,一个是取巧的办法 将附件和主件的搭配情况全部组合 变成分组背包 然后用分组背包的方法做..我一开始也是这么做的 代码太长了...:
#include<bits/stdc++.h>
using namespace std;
int n,m,temp,x;
int f[40000]={0};
int b[40000]={0};
struct things
{
int price,value,fushu,team;
}th[120];
bool mycup(things a,things b)
{
return ((a.team<b.team)||((a.team==b.team)&&(a.fushu<b.fushu)));
}
inline void chuli()
{
for(int i=1;i<=m+x;i++)
if(th[i].team!=th[i-1].team) b[i]=1;
else if(th[i].team!=th[i-2].team) b[i]=2;
else if(th[i].team!=th[i-3].team) b[i]=3;
for(int i=1;i<=m+x;i++) if(b[i]==1) th[i].team=i;
else if(b[i]==2) th[i].team=i-1;
else if(b[i]==3) th[i].team=i-2;
}
inline void chuli2()
{
for(int i=2;i<=m+x;i++)
if(th[i].team==th[i-1].team)
if(th[i].team==th[i-2].team) f[i-2]++;
else f[i-1]++;
}
inline void beibao()
{
for(int i=1;i<=m+x;i++)
for(int j=n;j>=1;j--)
for(int k=1;k<=m+x;k++)
if((th[k].team==i)&&(j>=th[k].price))
f[j]=max(f[j],f[j-th[k].price]+th[k].value);
return;
}
inline void fenzu()
{
int s=0;x=0;
while (s<temp)
{
s++;
if (f[s]==1)
{
th[s+1].price+=th[s].price;th[s+1].value+=th[s].value; th[s+1].team=s;
}
if(f[s]==2)
{
th[s+1].price+=th[s].price;th[s+1].value+=th[s].value; th[s+1].team=s;
th[s+2].price+=th[s].price;th[s+2].value+=th[s].value; th[s+2].team=s;
x++;
th[m+x].price=th[s+1].price+th[s+2].price-th[s].price;
th[m+x].value=th[s+1].value+th[s+2].value-th[s].value;
th[m+x].fushu=s;
th[m+x].team=s;
}
}
for(int i=1;i<=m;i++) f[i]=0;
return;
}
int main()
{
scanf("%d%d",&n,&m);
temp=0;
for(int i=1;i<=m;i++)
{
int t;
scanf("%d%d%d",&th[i].price,&t,&th[i].fushu);
th[i].value=th[i].price*t;
if(th[i].fushu==0) th[i].team=i;
else th[i].team=th[i].fushu;
if(th[i].team>temp) temp=th[i].team;
}
sort(th+1,th+1+m,mycup);
chuli();
chuli2();
fenzu();
sort(th+1,th+1+m+x,mycup);
beibao();
cout<<f[n];
return 0;
}
我不知道什么意念支撑我打完了这个代码... 之后看了老师和大佬的代码才觉得我的做法是多么愚蠢....老师标程如下:
int n,m;
int f[41000],a[41000];
int v[70],w[70],q[70];
void init() //读入数据
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&v[i],&w[i],&q[i]);
w[i]*=v[i]; //价值
}
}
void work()
{
for (int i=1;i<=m;i++)
//如果是主件,对里边的物品做01背包
if (q[i]==0)
{ //a数组是临时数组,表示第i个物品作为主件必须要。
for (int j=1;j<=v[i];j++) a[j]=0;
for (int j=v[i];j<=n;j++) a[j]=f[j-v[i]]+w[i];
//找第i个物品的附件,做0/1背包。只有主件必须要,再做附件的0/1背包。
for (int j=1;j<=m;j++)
if (q[j]==i)
for (int k=n;k>=v[i]+v[j];k--)
if (a[k-v[j]]+w[j]>a[k])
a[k]=a[k-v[j]]+w[j];
for (int j=v[i];j<=n;j++)//再对第i个物品再做一次0/1背包。
if (a[j]>f[j]) f[j]=a[j];
}
}
int main()
{
init();
work();
printf("%d\n",f[n]);
return 0;
}
感觉对背包嗑的不是特别的透彻 过两天回头再把这些题目打一遍 消化消化背包的精髓....