【挑战程序设计竞赛】- 2.1搜索(递归、栈、队列、dfs、bfs、剪枝)

(POJ不好用万能头文件)

2.1搜索

递归搜索

求阶乘/斐波那契,优化使用记忆化存储数组

int memo[MAXN];

int fib(int n){
    if(n<=1) return n;
    if(memo[n] != 0) return memo[n];
    return memo[n] = fib(n-1)+fib(n-2);
}

后进先出,Last In First Out。有底的桶,只能在上边取上边放。

c++标准库中,pop/push:

#include<stack>
stack<int> mys;
mys.empty();//是否非空
mys.push(1);//{1}放入栈顶
mys.push(2);//{1,2}
mys.top();//返回栈顶
mys.pop();//{1}去除栈顶
mys.size();
stack<int> yours;
mys.swap(yours)//交换两个栈中的所有元素

队列

先进先出,First In First Out。没底的桶,上边放下边取。

c++标准库里常用:

#include<queue>
queue<int> que;
que.push(1);//{1}放入队尾
que.push(2);//{1,2}
que.front();//队首
que.pop();//{2}去除

深度优先搜索

思想是不断地转移状态,如果如法转移就退回前一步状态,直到找出最终解。用递归函数实现。

(隐约相当于栈)

例1部分和:给定整数a1, a2, …, an,选出若干数和恰好为k。

每个数决定加或不加,复杂度 O ( 2 n ) O(2^{n}) O(2n)

int a[MAXN];
int n,k;
bool dfs(int i, int sum){
	if( i==n ) return sum==k;
	//不加a[i]
	if( dfs(i+1, sum) ) return true;
	//加a[i]
	if( dfs(i, sum+a[i]) ) return true;
	return false;
}

例2 POJ2386:有一大小为N*M的园子,雨后积水。八连通的积水认为连续。问有多少片水洼。‘W’表积水,’.'表陆地。(N,M<=100)

#include<cstdio> //(POJ不好用万能头文件)
#include<iostream>
using namespace std;
const int MAXN=110,MAXM=110;
int N,M;
char mp[MAXN][MAXM];
int dx[]={-1,-1,-1,0,0,0,1,1,1};
int dy[]={-1,0,1,-1,0,1,-1,0,1};
void dfs(int x,int y){
    mp[x][y]='.';
    for(int i=0; i<9; i++){
        int nx = x+dx[i], ny = y+dy[i];
        if(nx >= 0 && nx < N && ny >= 0 && ny < M && mp[nx][ny]=='W'){
            dfs(nx,ny);
        }
    }
}
int main(){
    while(~(scanf("%d%d",&N,&M))){
        for(int i=0;i<N;i++){
            scanf("%s",mp[i]);
        }
        int res = 0;
    	for(int i=0;i<N;i++){
        	for(int j=0;j<M;j++){
            	if(mp[i][j]=='W'){
                	dfs(i,j);
                	res++;
            	}
        	}
    	}
    	printf("%d\n", res);
    }
}

宽度优先搜索

对初始位置,由近及远地进行搜索。可以求最短路径、最少操作之类的。

用队列实现。

首先讲所有距离初始记为INF(=0x3f3f3f3f),搜索过程不断调整:d[nx][ny]=min(d[nx][ny],d[x][y]+1)
经过搜索后如果还是INF,就是不可达。

例1 迷宫:给定N*M的迷宫,每一步可向相邻四格移动。求起点到终点最小步数。
N,M<=100, ‘#’, ‘.’, ‘S’, 'G’分别表示墙壁、通道、起点、终点。

const int INF = 0x3f3f3f3f, NMAX=110, MMAX=110;
typedef pair<int, int> P;
char mp[NMAX][MMAX];
int N,M;
int sx,sy,gx,gy;
int d[NMAX][MMAX];

int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};

int bfs(sx,sy,gx,gy){
    queue<P> q;
    for(int i=0; i<N; i++)
        for(int j=0; j<M; j++)
            d[i][j]=INF;
    q.push(P(sx,sy));
    d[sx][sy]=0;
    
    while(!q.empty()){
        P now = q.front();
        q.pop();
        if(p.first==gx && p.second==gy) break;
        for(int i=0;i<4;i++){
            int nx = p.first+dx[i], ny = p.second+dy[i];
            if(nx>=0 && nx<N && ny>=0 && ny<M 
               &&mp[nx][ny]!='#' && d[nx][ny]==INF){
                q.push(P(nx,ny));
                d[nx][ny] = d[p.first][p.second]+1;
            }
        }
    }
    return d[gx][gy];
}

例2 特殊状态枚举,next_permutation函数

#include <cstdio>
#include <cstring>
using namespace std;
const int NMAX=15;
bool used[NMAX];
int perm[NMAX];
void permutation(int pos, int n){
	if(pos==n){
		for(int i=0;i<n;i++){
			printf("%d ", perm[i]);
		}printf("\n");
		return;
	}
	for(int i=0; i<n; i++){
		if(!used[i]){
			perm[pos]=i;
			used[i] = true;
			permutation(pos+1,n);
			used[i] = false;
		}
	}
	return;
}
int main(){
    int p;
    while(~scanf("%d",&p)&&p){
    	memset(used,0,sizeof(used));
        permutation(0,p);
    }
}

剪枝

如深度优先-例1部分和:如果给定条件是数字都大于0,那么如果当前和超过k,必然不可能使和为k。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值