8.19(军训DAY 3)

军训第三天 继续背包....

先完成的是昨天二维费用的题目  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;
}
感觉对背包嗑的不是特别的透彻   过两天回头再把这些题目打一遍  消化消化背包的精髓....

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值