计蒜客 联想专卖店大促销

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fuckingone/article/details/82117356
联想专卖店准备进行大促销,每位进店购买电脑的顾客都能获得奖品大礼包。一共有三种备选奖品:U盘、鼠标和机械键盘。一共有三种礼包配置:

豪华礼包:一个 U盘、一个鼠标和一个机械键盘。

幸运礼包:一个 U盘、两个鼠标。

普通礼包:两个 U盘、一个鼠标。

现在专卖店内准备了 aa 个 U盘、bb 个鼠标和 cc个机械键盘。为了给顾客带来足够多的惊喜,店长希望 相邻两位领礼包的顾客拿到的礼包类型都是不同的。店长想知道这些奖品最多可以发出多少份礼包。

输入格式

第一行一个正整数 T(1 \leq T \leq 10^5)T(1≤T≤105) 表示数据的组数。

每组数据一行三个正整数 a,b,c(0 \leq c \leq b \leq a \leq 10^5)a,b,c(0≤c≤b≤a≤105),表示 U盘、鼠标和机械键盘各有多少个。

所有 a,b,ca,b,c 的总和不超过 10^7107。

输出格式

每组数据输出一个整数,表示最多能发出多少份礼包。

样例输入

2
4 4 0
1 1 1
样例输出

2
1

借鉴了一下:https://blog.csdn.net/fsss_7/article/details/51873556

              https://blog.csdn.net/u014325920/article/details/51912622

     https://www.statusrank.xyz/ https://blog.csdn.net/HowardEmily/article/details/72855976

1.我们去二分礼包的数量为mid。然后剪掉对应得到a-mid,b-mid,c。现在组成第一种礼品的是0 0 1,组成第二种礼品的是0 1 0,组成第三种礼品的是1 0 0。然后我们去枚举第一种礼品的数量,判断第一种和第二种和第三种的组成是否符合要求,就ok啦!!!

2.考虑礼包数最多的那个设为w,那么就需要w-1种其他的来插进去,所以就要保证最小x和次小的礼包个数y,满足x+y+1>=w,也就是说x+y最多满足x+y+1个最多的礼包不相邻,所以我们check时候只需要比较最小值+次小值+min(最小值+次小值+1, 最大值)与x的大小关系即可。

3.那么我们直接二分能凑出的最多满足条件的套餐即可。


#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
int d[5];
int pd(int a,int b,int c,int g) {
    int i,k=0;
    d[++k]=min(c,g);
    d[++k]=min(a-g,g);
    d[++k]=min(b-g,g);
    sort(d+1,d+k+1);
    return d[1]+d[2]+min(d[1]+d[2]+1,d[3])>=g;  
}
int main()
{
    int a,b,c,t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &a, &b, &c);
        int l=-1,r=b+1,mid=(l+r)>>1;
        while (l+1<r)      //边界最小+1<边界最大
        if (pd(a,b,c,mid)) { l=mid;mid=(l+r)>>1; }  //mid小
        else { r=mid;mid=(l+r)>>1; }     //mid大
        printf("%d\n", l);
    }
    return 0;
}

二分法:

其实就是一种通过不断的排除不可能的东西,来最终找到需要的东西的一种方法。所以可以理解成排除法。

之所以叫二分,是因为每次排除都把所有的情况分成"可能"和"不可能"两种,然后抛弃所有"不可能"的情况。

最正统的二分法中,是每次排除都可以排除掉一半的情况,这样子的寻找效率是很高的。

拓展资料:

定精确度ξ,用二分法求函数f(x)零点近似值的步骤如下:

1 确定区间[a,b],验证f(a)·f(b)<0,给定精确度ξ。

2 求区间(a,b)的中点c。

3 计算f(c)。

(1) 若f(c)=0,则c就是函数的零点;

(2) 若f(a)·f(c)<0,则令b=c;

(3) 若f(c)·f(b)<0,则令a=c。

(4) 判断是否达到精确度ξ:即若|a-b|<ξ,则得到零点近似值a(或b),否则重复2-4

列举法:

1,枚举算法的定义:

在进行归纳推理时,如果逐个考察了某类事件的所有可能情况,因而得出一般结论,那么该结论是可靠 的,这种归纳方法叫做枚举法。

2,枚举算法的思想是:

将问题的所有可能的答案一一列举,然后根据条件判断此答案是否合适,保留合适的,舍弃不合适的。

3,使用枚举算法解题的基本思路如下:

(1)确定枚举对象、范围和判定条件。

(2)逐一枚举可能的解并验证每个解是否是问题的解。

4,枚举算法步骤:

(1)确定解题的可能范围,不能遗漏任何一个真正解,同时避免重复。

(2)判定是否是真正解的方法。

(3)为了提高解决问题的效率,使可能解的范围将至最小,

5,枚举算法的流程图如下所示:

                                       


二,枚举算法实例

例一:百钱买白鸡

1,问题描述:

公鸡每只5元,母鸡每只3元,三只小鸡1元,用100元买100只鸡,问公鸡、母鸡、小鸡各多少只?

2,算法分析:

利用枚举法解决该问题,以三种鸡的个数为枚举对象,分别设为mj,gj和xj,用三种鸡的总数 (mj+gj+xj=100)和买鸡钱的总数(1/3*xj+mj*3+gj*5=100)作为判定条件,穷举各种鸡的个数。


#include<iostream>
using namespace std;
int main()
{
	int mj=0, gj=0, xj=0;                  //定义变量分别表示母鸡、公鸡、小鸡并初始化
	for (gj = 0; gj <= 20; gj++)		   //公鸡最多可买20个
	{
		for (mj = 0; mj <= 33; mj++)	   //母鸡最多可买33个
		{
			xj = 100 - gj - mj;			   // 三种鸡的总数是100只
			if (xj % 3 == 0 && 5 * gj + 3 * mj + xj / 3 == 100)    // 总花费为100元。
		    printf("公鸡为 %d 只,母鸡为 %d 只,小鸡为 %d 只!\n", gj, mj, xj);
		}
	}
	system("pause");
	return 0;
}

左移右移:

 对一个数实施左移操作=对这个数×2; 对一个数实施右移操作=对这个数÷2。

这个是计算机基本的二进制操作,因此不仅仅局限于C语言, 事实上绝大多数计算机编程语言都支持这个操作。

理解很容易:
一个(十进制的)数,在电脑里面都可以按二进制表示。 比如数字8, 二进制就是1000. 左移一位,1000 << 1 = 0001 0000 = 16, 因此就是=8×2;同理右移一位, 1000 >> 1 = 0100 = 4, 就是8÷2. 

猜你喜欢

转载自blog.csdn.net/fuckingone/article/details/82117356