5.23总结

二分法总结
什么是二分法?
算法:二分法查找适用于数据量较大时,但是数据需要先排好顺序。主要思想是:(设查找的数组区间为array[low, high])
(1)确定该区间的中间位置K(2)将查找的值T与array[k]比较。若相等,查找成功返回此位置;否则确定新的查找区域,继续二分查找。区域确定如下:a.array[k]>T 由数组的有序性可知array[k,k+1,……,high]>T;故新的区间为array[low,……,K-1]b.array[k]<T 类似上面查找区间为array[k+1,……,high]。每一次查找与中间值比较,可以确定是否查找成功,不成功当前查找区间将缩小一半,递归查找即可。时间复杂度为:O(log2n)。——百度百科

如何写出一个二分法?边界条件如何判断,到底是等于还是不等?很困恼,比如说查找第一个等于5的数,那又在如何查找呢?查找最后一个等于5的数,又该如何改变?
总结了四个步骤

  1. 判定条件为start+1小于end,start=0, end=size-1
  2. mid=start+((end-start)>>1)
  3. 如果data[mid]满足条件直接返回,如果满足条件的数据在mid的右边则将start=mid,如果满足条件的数据在mid左边则将end=mid
  4. 根据条件再次判定start,end两个元素是否满足条件
    其实整个过程就不断缩小范围的过程,最后一步就是将整个数组的范围缩小到start end两个元素而已。

这里第3步有一个小的窍门就是不管什么情况下都应该单独判data[mid]大于等于和小于的情况,而不应该合并,因为会比较容易出错。

作业总结:(https://vjudge.net/contest/439261
W.
二分思想不仅仅用于二分查找哦,本题感觉难在理解题意。需要注意的是,饼的所以饼的体积取值应该是0到max间任意值,因为蛋糕不能拼凑可以多余,深入的想想就知道分到蛋糕最大的情况应该是找到一个极值,然后部分蛋糕根本不需要用上,部分蛋糕会有多余。想到这个后这个体积极值就顺利成章要用二分求了,因为没有具体的元素个数,直接的顺序查找来求极值的方法用不了的。 本来是想枚举所有将蛋糕完整分给每个人的情况,但是这样做是不会比正确解法分得的蛋糕多的。
AC代码:

#include <iostream>
#include <stdio.h>
#include<math.h>
#define pi acos(-1.0)//准确定义Π的值
using namespace std;
//思路是对0到max二分查找,根据大小算人数,人数与f+1比较后改变查找边界,因为蛋糕不能拼凑可以多余,所以饼的体积取值应该是0到max间任意值,一开始没有注意到这点,所以不能枚举要二分查找逼近那个值
int main()
{int n,t,f,i,r,pep;
    double s[10005];
    double max,min,mid;
    cin>>t;
    while(t--)
    {
        min=0;max=0;
        cin>>n>>f;
        f++;
        for(i=1;i<=n;i++)
            {
            cin>>r;
            s[i]=pi*r*r;
            if(max<s[i]) max=s[i];
            }
        while(max-min>1e-7)
        {   pep=0;
            mid=(max+min)/2;
            for(i=1;i<=n;i++)
            pep+=(int)(s[i]/mid);//s[i]/mind一定要有括号,才是对整体强制转换
            if(pep>=f)
                min=mid;
            else max=mid;
        }
        printf("%.4lf\n",mid);

    }
}

B.
该题是,判断一个新输入字符串是否属于原先字符串序列
1.“不属于” :打印"OK"表示插入成功
2.“属于”:判断是第几次出现该串(序列号)并打印:“该串”+序列号
方法:map <string, int>
这个题使用map之后就变的非常简单了
AC代码:

#include<iostream>
#include<map>
#include<string.h>
using namespace std;
int main()
{
    map<string,int>mp;
    string s;
    int t;
    while(cin>>t)
    {
        for(int i=0;i<t;i++)
        {
            cin>>s;
            if(mp[s]==0)
            {
                cout<<"OK\n";
                mp[s]++;
            }
            else
            {
                cout<<s<<mp[s]<<endl;
                mp[s]++;
            }
 
        }
    }
    return 0;
 
}
    

M.
题意
有n个人体检,每个人要检查k个项目,有m个医生,每个医生检查每个人的一个项目需要花费1分钟,问检查完所有的人最少需要花费多长时间。要求:每个医生每次只能检查一个人的一个项目,每个人同一分钟只能接受一个医生检查一个项目。
思路:
很容易想到二分。每个人都有k个项目,最小的时间为k分钟,如果比k小的话,肯定存在同一分钟有一个人检查了超过两个项目,不和题意。考虑最坏的情况,只有一个医生的话,需要花费n*k分钟。然后对于第一个医生,可以这样构造,他的mid分钟一次检查a11,a12,a13…a1k然后a2(k+1)…a2mid,如此类推。这样可以把每个医生的就诊单序列给出来。当然每个人的检查项目的数量也可以不同。
AC代码:

#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;
int main()  
{	
	int t,n,k,m,sum;
	cin>>t;
	while(t--)
	{	sum=0;
		cin>>n>>k>>m;
		if(m>=n)
			  sum+=k;
		else	
		{	
			if((n*k)%m==0)
			sum+=(n*k)/m;
			else
			{
				sum+=(n*k)/m;
				sum+=1;
			}
		}
		cout<<sum<<endl;
	}
	
    return 0;  
}

K.
题意
把C头牛放到N个带有编号的隔间里,使得任意两头牛所在的隔间编号的最小差值最大。例如样例排完序后变成1 2 4 8 9,那么1位置放一头牛,4位置放一头牛,它们的差值为3;最后一头牛放在8或9位置都可以,和4位置的差值分别为4、5,和1位置的差值分别为7和8,不比3小,所以最大的最小值为3。
分析:
这是一个最小值最大化的问题。先对隔间编号从小到大排序,则最大距离不会超过两端的两头牛之间的差值,最小值为0。所以可以通过二分枚举最小值来求。假设当前的最小值为x,如果判断出最小差值为x时可以放下C头牛,就先让x变大再判断;如果放不下,说明当前的x太大了,就先让x变小然后再进行判断。直到求出一个最大的x就是最终的答案。
其实关键就在于讨论差值的大小。
AC代码:

#include <iostream>
#include <algorithm>
using namespace std;
int n,c;
int a[100010];
int judge(int x)
{
	int now=1; 
	int cnt=1; 
	for(int i=2;i<=n;i++)
	{
		if(a[i]-a[now]>=x)
		{
			cnt++;now=i;
		}
	}
	if(cnt>=c) 
	return 1;
	else
	return 0;
}
int main()
{
	int L,R,ans;
	cin>>n>>c;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	sort(a+1,a+1+n);
	L=0;R=a[n]/c+1;
	while(L<=R)
	{
		int mid=(L+R)/2;
		if(judge(mid))
		{
			ans=mid;
			L=mid+1; 
		}
		else
			R=mid-1;
	}
	cout<<ans<<endl;
	return 0;
}

感悟:
漫漫ACM路,大一就要告一段落了,不知道以后还有没有机会接触ACM,但是选ACM确实让我学到了不少东西啊,明白了什么是算法,从一开始的贪心,还记得当时贪心做了一天才做了两道题,而且第二道题还死活出不来,当时都有放弃的想法了,想为什么选ACM啊,这不折磨人吗,但是慢慢的掌握了做题的技巧,一道题不会再去研究一下午而没有思路了,因为可以找题解啊~嘿嘿嘿…可以从题解上学习别人的思路,从而可以形成一个大致的模板,从贪心到线性DP,区间DP,再到背包问题,二分法,递归…其实每个算法都有一定的规律可循,每种题型都有一个大致的模板可用,也就这么多了,还有太多想说的,都在之前的博客上说了,这篇博客,就这样了事了。
ACM,后会有期

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值