死宅日志——搜索1

搜索的前提是,我们始终相信总能搜索到结果。搜索不到也是搜索的一种结果

。搜索主要方法主要有两种,枚举法和回溯法。枚举,我们事先知道结果或约束条件范围,典型例子就是暴力穷举。优点是,简单容易理解,但是,往往效率就比较低。

回溯法经常用于,我们不知道求解过程中会走到哪一步,但是目的明确,步与步之间有一定的相似关系。经常是用多重循环来实现。

由于直译枚举或者暴力穷举,是考察大量状态,穷举所有状态。所以是思考量最小的,最简单易懂的。经常是用多重循环来实现。往往通过降维来提升效率,降低时间复杂度。这里来举个例子。


SubRaY有一天得到一块西瓜,是长方体形的…(我的世界吗)

[题目描述]SubRaY发现这块西瓜长m厘米,宽n厘米,高h厘米.他发现如果把这块西瓜平均地分成mnh块1立方厘米的小正方体,那么每一小块都会有一个营养值(可能为负,因为西瓜是有可能坏掉的,但是绝对值不超过200).

现在SubRaY决定从这mnh立方厘米的西瓜中切出mmnnhh立方厘米的一块小西瓜(一定是立方体形,长宽高均为整数),然后吃掉它.他想知道他最多能获得多少营养值.(0<=mm<=m,0<=nn<=n,0<=hh<=h.mm,nn,hh的值由您来决定).

换句话说,我们希望从一个mnh的三维矩阵中,找出一个三维子矩阵,这个子矩阵的权和最大.


Example Input


2 3 4


4 1 2 8


0 5 -48 4


3 0 1 9


2 1 4 9


1 0 1 7


3 1 2 8


Example Output


45

看到这道题,第一个想法是枚举所有大小的西瓜,每一种切法切出来的西瓜,在计算它的营养值进行比较。

但是想一想,不就是个求和吗。计算从点1,1,1到点x,y,z的累加和并记录在sum[i,j,k]。然后枚举西瓜的左上角和右下角的点。Result=Sum[i,j,k]-……这个我不想算了,自己拿着演草纸画画算出来那个公式都行了。。。

二分枚举的前提是,数列是具有单调性的。穷举之前先排个序,甚至本身就是有序。通常是求满足条件的最佳值。可以用while循环来写也可以用递归来写。

left := 1; right := n;
while (left<right) do
{
    mid := (left+right)/2;
     if (条件) left := mid + 1;
               else right := mid;
}

因为二分是折半之后再折半,所以二分的时间复杂度是 log2(n)。这是一个很强大的效率:

 n=1024,               log2(n)=10;

 n=1024*1024            log2(n)=20;

所以,数据量越大,二分的优越性越明显。

回溯法是一种能避免不必要搜索的穷举式的搜索算法。通常是用多重循环来实现。例如经典的八皇后问题。

Floodfill算法

Floodfill种子染色法也属于回溯发。它就像一滴墨水滴进自来水一样慢慢扩散出去或感染它周围的区域。floodfill可以用递归来写,也可以用队列来写,相对来说,用借助于队列来写会更稳定一点。这里举个例子:

Cell


一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如阵列:

输入:整数m,n(m行,n列 (0<m,n<=100))矩阵
输出:细胞的个数。

样例:
输入:
4 10
0234500067
1034560500
2045600671
0000000089

输出:
4

这道题就是找有几片非0的区域
Int dx[1…4]=(-1,0,1,0);//dx,dy是当前点坐标x,y可以变化的量
Int dy[1…4] =(0,1,0,-1);
用1到4的循环来上下左右找

For(int i:=0;i<4 ;i++)
{
	xx:=x+dx[i];  
	yy:=y+dy[i];
}  

从这一点出发将周围非0的点感染为0。代码如下:

#include <stdio.h>
#include <stdlib.h>
int
n,m,cx[4]={0,1,0,-1},cy[4]={1,0,-1,0};
char c[1010][1010];
void ff(int x,int y)
{
    int j=0;
    c[x][y]='0';
    for(;j<4;j++)
    	if(c[x+cx[j]][y+cy[j]]!='0'&&x+cx[j]>0&&x+cx[j]<=m&&y+cy[j]>0&&y+cy[j]<=n)    
            ff(x+cx[j],y+cy[j]);
}
int main()
{
    int sum=0,i,j;
    scanf("%d%d",&m,&n);
    for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)scanf(" %c",&c[i][j]);/*c而当前的scanf是在接收字符
(即用%c控制输入)时。由于前面的输入语句(不一定是scanf)把最后输入的'\n'遗留在了输入缓冲区就是它把回车当输入了*/
    for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
        if(c[i][j]!='0'){sum++;ff(i,j);}
    printf("有%d个细胞",sum);
    scanf("");//防止输出一闪而过
    return 0;
}

老师教的变成c了。。。。我也转了 不过vc++用起来好难受啊。。。没mingw和vs好用竟然还有bug。。。。差评

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值