[挖坑]搜索相关

算法中最基本和常用的是搜索,这里要说的是,有些初学者在学习这些搜索基本算法是不太注意剪枝,这是十分不可取的,因为所有搜索的题目给你的测试用例都不会有很大的规模,你往往察觉不出程序运行的时间问题,但是真正的测试数据一定能过滤出那些没有剪枝的算法。实际上参赛选手基本上都会使用常用的搜索算法,题目的区分度往往就是建立在诸如剪枝之类的优化上了。 
 什么是搜索算法呢?
搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。
搜索过程实际上是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的节点的过程。

第一部分:二分查找

假设给出若干个(可以很多)有序的整数,请查找某个元素是否存在,比如——

2   3   4   5   6   8   12  20  32  45  65  74  86  95  100

请查找以上数列中是否存在某个整数(比如25),若有,请输出其位置,否则请输出NO~

二分查找的前提—— 数据的单调性

时间复杂度:O(logN)

例题:HDOJ-2199

地址:http://acm.hdu.edu.cn/showproblem.php?pid=2199

代码:

#include<cmath>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#define  Y(x) 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6-y
using namespace std;
int n, m;
int sum;
int main()
{
    double s = 0, e = 100, y;
    int t;
    cin>>t;
    while(t--)
    {
        s = 0;
        e = 100;
        cin>>y;
        if(Y(e)>=0&&Y(s)<=0)
        {
            while(e-s>1e-6)
            {
                if(Y((s+e)/2)>1e-10)
                    e = (s+e)/2 - 1e-7;
                else
                    s = (s+e)/2 + 1e-7;
            }
            printf("%.4lf\n", (s+e)/2);
        }
        else
            cout<<"No solution!"<<endl;
    }
}

例题:HUOJ-2899

地址:http://acm.hdu.edu.cn/showproblem.php?pid=2899

思考:非一般的查找原函数零点,而是搜寻最值。即查询导函数的零点~

代码:

#include<cmath>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#define  AY(x) 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*x*x-y*x
#define  CY(x) 42*pow(x,6)+48*pow(x,5)+21*pow(x,2)+10*x-y
using namespace std;
int n, m;
int sum;
int main()
{
    double s, e, y;
    int t;
    cin>>t;
    while(t--)
    {
        s = 0;
        e = 100;
        cin>>y;
        while(e-s>1e-6)
        {
            if(CY((s+e)/2)>1e-10)
                e = (s+e)/2 - 1e-7;
            else
                s = (s+e)/2 + 1e-7;
        }
        printf("%.4lf\n", AY((s+e)/2));

    }
}


三分查找,略



#include<cmath>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
char s[9][9];
int n, m, d1, d2, t;
int me[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
bool escape;
int dfs(int s1, int s2, int cnt)
{
	int i, temp;
	if(escape)
		return 0;//已经符合条件,退出
	if(s1>n||s2>m||s1<=0||s2<=0)//越界,退出
		return 0;
	if(cnt==t&&s1==d1&&s2==d2)
		escape = 1;
	temp=(t-cnt)-abs(s1-d1)-abs(s2-d2); 
	if(temp<0||temp%2)//剪枝一
		return 0; 
	for(i=0;i<4;i++)
	{
		if(s[s1+me[i][0]][s2+me[i][1]]!='X')
		{
			s[s1+me[i][0]][s2+me[i][1]]='X';//表示已走过
			dfs(s1+me[i][0],s2+me[i][1],cnt+1);
			s[s1+me[i][0]][s2+me[i][1]]='.';//复原
		}

	}
	return 0;
}
int main()
{
	int i, j, wall;
	int s1, s2;
	while(cin>>n>>m>>t,n+m+t)
	{
		escape = 0;
		memset(s,'X',81*sizeof(char));
		wall = 0;
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
			{
				cin>>s[i][j];
				if(s[i][j]=='S')
				{
					s1=i;
					s2=j;
				}
				else if(s[i][j]=='D')
				{
					d1=i;
					d2=j;
				}
				else if(s[i][j]=='X')
					wall++;
			}
			if(n*m-wall<=t)  //剪枝二
			{  
				cout<<"NO"<<endl;  
				continue;  
			} 
			s[s1][s2]='X';//初始位置不可再走
			dfs(s1,s2,0);
			puts(escape?"YES":"NO");
	}
	return 0;
}

嘛, 剪枝要详细点写

剪枝一

那么设所在位置 (s1,s2) 与 目标位置 (d1,d2)
如果abs(d1-s1)+abs(d2-s2) 为偶数,则说明 abs(d1-s1)+和 abs(d2-s2)的奇偶性相同,需要走偶数步.
如果abs(d1-s1)+abs(d2-s2)为奇数,那么说明 abs(d1-s1)和 abs(d2-s2)的奇偶性不同,需要走奇数步.
解为 abs(d1-s1)+abs(d2-s2)的奇偶性就确定了所需要的步数的奇偶性!!
而 (t-cnt)表示剩下还需要走的步数,由于题目要求要在 t时恰好到达,

那么(t-cnt)abs(d1-s1)+abs(d2-s2) 的奇偶性必须相同

因此 temp=t-cnt- abs(d1-s1)+abs(d2-s2)必然为偶数!

剪枝二

这个比较简单也没什么大用, 约定时刻走过的方块数加上墙的个数应当小于总区域面积。


inline double Y(double x)
{
	return SomethingAboutX;
}
const double eps = 1e-6;
double BinSearch(double start, double end, double K )
{
	double mid;
	if(fabs(Y(start)-K)<eps)  
		return start;
	if(fabs(Y(end)-K)<eps)
		return end;
	while(fabs(end-start)>eps)
	{
		mid = (start + end)/2 ;
		if(Y(mid)-K>eps)  
			end = mid - eps; 
		else
			start = mid + eps;
	}
	return (start+end)/2;
}


你可能感兴趣的:(算法,优化,测试,扩展)