【YbtOj】最大费用
题目链接:http://noip.ybtoj.com.cn/contest/17/problem/1
挺简单的一道深搜题目。
Saction A 输入/数据处理
有两种输入的方法,分别对应两种不同的搜索。
第一种,一次性将n个数据全部读入,然后依次枚举每个商品是买还是不买,从中选出比m小的最大价值和就行了,但是其时间复杂度为O(2n),肯定会TLE或者MLE。
第二种,分两批读入,而然是爆搜,但其时间复杂度降低到了O(n*2n/2),相比第一种,肯定划算。
既然是分两批读入,那么就是从中间一刀切。但我们不能直接写n/2,因为当n是奇数的时候很容易造成数据遗漏导致输入不完整,此刻用位运算无疑是最好的选择:n>>1。
我们定义第一次读入u个数据,第二次读入v个数据,用a数组存储商品价值,那么就有:
1 cin>>n>>m; 2 u=n>>1; 3 for(int i=1;i<=u;++i) 4 cin>>a[i]; 5 dfs(0,1,u,0); 6 v=n-u; 7 for(int i=1;i<=v;++i) 8 cin>>a[i]; 9 dfs(1,1,v,0);
Saction B 搜索
既然是水题一个,那么搜索的框架自然非常简单。
首先来确定一下搜索的终止条件。很明显当深度超过一批(有两批嘛)商品的总数时,就应该退出搜索或者说回溯,这个只用一个if判断一下就行了。在这个if当中,我们需要记载这一次搜索的结果,由于我们把商品分成了两批,所以得开个二维数组来存。定义这个数组的名称为c,其第一个下表变量表示第几批商品,第二个下标变量(准确说是这个下标变量所指向的数组位置)表示这次搜索的结果。
此时我们只用在开一个int型变量和一位数组就能把控全局。毫无疑问,这个int型的变量是用来记录这是第几批商品的,我们将其命名为bo,则这个bo的值只有0或者1(注意数组的存储是从0开始的)。
这个int型的变量解决了c数组的第一个下标变量。第二个下标变量是需要不断变化的,虽然这个变化是递增,但我们仍然能够通过一个巧妙的数组转化达到目的:一位数组b。这个数组的下标变量的含义和bo其实是一样的,只是充个数而已。
我们规定dfs函数的第一个值为bo,第二个值表示深度(我们用x表示),第三个值表示商品个数(用t表示),第四个值表示已选商品价值总和(用s表示)。
假设bo=0,我们进行第一批商品的搜索。因为每个商品只有选或者不选两种选择,所以写两个递归放在一起就行了。第一个递归里面s不变,表示不选,深度x+1.
第二个递归里面,s改变,表示选,并且s的值要加上a[x],即当前搜索的商品的价值,接着x+1。
当x>t的时候,我们需要记录本次搜素的结果,也就是把s的值放入c数组里面。为了实现存下所有的s,也就是c数组的第二个变量的递增,我们使用++b[bo],给个程序更直观:
1 int b[2]; 2 if(x>t) 3 { 4 c[bo][++b[bo]]=s; 5 return; 6 }
看到了吗,“++”表示先加在进行取数,在程序中,b[bo]的值在不断的递增,并且递增的值还是表示第一批商品的位置,也就是下标变量为bo的位置,嗯,真是机智!
Saction C 整合答案/输出
在整个搜索结束之后,我们得到了数组c,里面有两批商品所有的组合情况,现在需要对它们进行答案合并。
怎么合并呢?
简单,我们选择一批的数据,取出里面小于m的值,在另一组里面找出与其相加小于m的数据,然后将这样的数据汇聚在一起,选出里面的最大值即可。
我们定义答案为ans,选择第一批数据开始遍历(就是打个for循环),第一批数据的数据量为b[0]的值(很妙吧),用if判断出小于m的值。
一旦找到我们就可以开始寻找第二个数据了。但是问题来了,当第二个数据和第一个数据的量非常大时怎么办?简单,在c++里面有一个叫做upper_bound()的函数,他可以找到第一个大于待查找数值的位置,其用法如下:
1 //upper_bound(起始地址,结束地址,要查找的数值)
在这个查找之前,我们最好使用sort将第二批数据处理排序一遍,这样结合upper_bound就可以轻松解决。剩下的就是一些鸡毛蒜皮的小事了。
完整代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1.3e6; 4 int n,m,u,v; 5 int a[maxn],b[2],c[2][maxn]; 6 void dfs(int bo,int x,int t,int s) 7 { 8 if(x>t) 9 { 10 c[bo][++b[bo]]=s; 11 return; 12 } 13 dfs(bo,x+1,t,s); 14 dfs(bo,x+1,t,s+a[x]); 15 } 16 int main() 17 { 18 cin>>n>>m; 19 u=n>>1; 20 for(int i=1;i<=u;++i) 21 cin>>a[i]; 22 dfs(0,1,u,0); 23 v=n-u; 24 for(int i=1;i<=v;++i) 25 cin>>a[i]; 26 dfs(1,1,v,0); 27 sort(c[1]+1,c[1]+b[1]+1); 28 int ans=0; 29 for(int i=1;i<=b[0];++i) 30 { 31 if(m>=c[0][i]) 32 { 33 int x=upper_bound(c[1]+1,c[1]+b[1]+1,m-c[0][i])-c[1]-1; 34 ans=max(ans,c[0][i]+c[1][x]); 35 } 36 } 37 cout<<ans; 38 return 0; 39 }