Class 06 搜索

枚举

枚举范围

  • 枚举的边界要设定好

数据规模

  • 枚举要保证数据规模在时间限制内能够枚举完

枚举方式

  • 枚举顺序有时会影响时间

NOIP 2001 一元三次方程

问题描述
有形如: a x 3 + b x 2 + c x + d = 0 ax^3+bx^2+cx+d=0 ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根 (根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。
提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f(x2)<0,则在(x1,x2)之间一定有一个 根。

样例
输入:1 -5 -4 20
输出:-2.00 2.00 5.00

枚举,用区间[-100, 100]枚举

#include<cstdio>
using namespace std;

const double eps=0.01;
double a,b,c,d;

int main() {
     scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
     for(double x=-100.00;x<=100.00;x+=eps) {
         double f=a*x*x*x+b*x*x+c*x+d;
         if(f>=(-0.001) && f<=(0.001)) printf("%.2lf ",x);
     }
     return 0;
}

NOIP 2011 铺地毯

题目描述
为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯,一共有n张地毯,编号从 1 到n。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。
地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

输入
输入共 n+2行。
第一行有一个整数n,表示总共有 n张地毯。
接下来的 n行中,第 i+1行表示编号 i的地毯的信息,包含四个正整数 a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在 x轴和 y轴方向的长度。
第 n+2 行包含两个正整数 x 和 y,表示所求的地面的点的坐标(x,y)。

输出
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。

输入
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2
输出
3

输入
3
1 0 2 3
0 2 3 3
2 1 3 3
4 5
输出
-1

从最后一个地毯开始遍历,在这个正方形内,就输出,不再就往前一个地毯遍历

#include<bits/stdc++.h>
using namespace std;
int n,a[11000],b[11000],g[11000],k[11000],x,y;
int main()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i++){
        scanf("%d%d%d%d",&a[i],&b[i],&g[i],&k[i]);
    } 
    scanf("%d%d",&x,&y);
    for (int i = n;i >= 1;i--){
        int you = a[i] + g[i];
        int shang = b[i] + k[i];
        if (x >= a[i] && y >= b[i] && x <= you && y <= shang){
            printf("%d\n",i);
            return 0;
        }
    }
    printf("-1\n");
    return 0;
}

DFS

框架

void dfs(参数)
{
	if(越界或者不合法状态)returnif(当前为终点/边界){
		进行输出或计数统计答案等操作
		return//终止当前函数
	}
	for(枚举当前所有方案){
		if(当前方案合法/当前方案没有被标记过){
			记录当前方案标记当前方案
			dfs(下一个位置)
			还原标记
		}
	}
}

输出全排列

给出一个n,输出1-n的全排列

#include<bits/stdc++.h>
using namespace std; 

const int MAX = 20;
bool marked[MAX];
int ans[MAX];
int n;

void dfs(int level){
	if(level > n) {
		for(int i=1; i<= n; i++){
			printf("%d", ans[i]);
		}
		printf("\n");
		return;
	} 
	for(int i=1; i<=n; i++){
		if(marked[i]) continue;
		marked[i] = 1;
		ans[level] = i;
		dfs(level + 1);
		marked[i] = 0;
	}
}


int main(){

 	cin>>n;
 	dfs(1);
	return 0;	
} 

经典寻路问题

题目
N个城市,编号 1 到 N 。城市间有 R 条单向道路。每条道路连接两个城市,有
长度和过路费两个属性。
Bob只有 K 块钱,他想从城市 1 走到城市 N 。问最短共需要走多长的路。如
果到不了 N ,输出 1
2<=N<=100; 0<K<=10000; 1<=R<=10000
每条路的长度L, 1 <= L <= 100; 每条路的过路费 T , 0 <= T <= 100

输入
输入的第一行包含整数K,0 <= K <= 10000,Bob可以在途中花费的最大硬币数。
第二行包含整数N,2 <= N <= 100,即城市总数。
第三行包含整数R,1 <= R <= 10000,道路总数。
以下R行中的每一行通过指定由单个空白字符分隔的整数S,D,L和T来描述一条道路:
S是源城市,1 <= S <= N.
D是目的地城市,1 <= D <= N.
L是道路长度,1 <= L <= 100
T是收费(以硬币数表示),0 <= T <= 100
请注意,不同的道路可能具有相同的源和目的地城市。

输出
输出的第一行和唯一一行应包含从城市1到城市N的最短路径的总长度,其总收费小于或等于K个硬币。如果此路径不存在,则只应将数字-1写入输出。

输入样例
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2

输出样例
11

// dfs + 剪枝


  • https://blog.csdn.net/yuanpengyuanpeng/article/details/105922842

加分二叉树

设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
  subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数。
  若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
  试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;
  (1)tree的最高加分
  (2)tree的前序遍历

输入格式
第1行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。

输出格式
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。

输入输出样例
输入样例#1:
5
5 7 1 2 10
输出样例#1:
145
3 1 2 4 5


BFS

二叉树的遍历

给出一个整数n ,表示一棵 n 个节点的二叉树,编号 1~n 。
根节点为1 号节点。接下来n 行每行给出两个整数 x,y 。表示节点 i 的左儿子和右儿子。 x=0 表示无左儿子,y=0 表示无右儿子。从1 号节点进行 BFS ,并输出遍历结果。

样例输入:
7
2 3
4 5
6 7
0 0
0 0
0 0
0 0
样例输出:
1 2 3 4 5 6 7

#include<bits/stdc++.h>
using namespace std; 

const int MAXN = 2000;

struct node{
	int le, re;
}t[MAXN];

void bfs(int level){
	queue<int> q;
	q.push(level);
	while(!q.empty()){
		int cur = q.front();
		printf("%d ", cur);
		q.pop();
		if(t[cur].le) q.push(t[cur].le);
		if(t[cur].re) q.push(t[cur].re);
	}
}


int main(){
	
	int n;
	cin>>n;
	for(int i = 1; i <= n; i++){
		scanf("%d%d", &t[i].le, &t[i].re);
	}
	bfs(1);
	
	return 0;
}

马的遍历

题目描述
有一个n*m 的棋盘 (1<n,m<= 400),在某个点上有一个马 要求你计算出马到达棋盘
上任意一个点最少要 走几步

输入格式
一行四个数据,棋盘的大小和马的坐标

输出格式
一个n*m 的矩阵,代表马到达某个点最少要走几步(左对齐,宽 5 格,不能到达则输出 -1) 。

输入样例
3 3 1 1
输出样例
0 3 2
3 -1 1
2 1 4

#include<bits/stdc++.h>
using namespace std; 

const int MAXN = 500;
bool marked[MAXN][MAXN];
int ans[MAXN][MAXN];
int dx[10] = {0, -1, -1, 1, 1, 2, 2, -2, -2};
int dy[10] = {0, -2, 2, 2, -2, 1, -1, 1, -1};
int n, m, px, py;


struct node{
	int x, y, v;
};

queue<node> q;

void bfs(node temp){
	q.push(temp);
	marked[px][py] = 1;
	while(!q.empty()){
		node cur = q.front();
		q.pop();
		int x = cur.x, y = cur.y, v = cur.v;
		for(int i=1;i<=8;i++){
			int xx = x + dx[i], yy = y + dy[i];
			if(xx < 1 || yy < 1 || xx > n || yy > m) continue;
			if(marked[xx][yy]) continue;
			marked[xx][yy] = 1;
			ans[xx][yy] = v + 1;
			temp.x = xx, temp.y = yy, temp.v = v + 1;
			q.push(temp);
			
		}
	}
}


int main(){
	scanf("%d%d%d%d", &n, &m, &px, &py);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++)
			ans[i][j] = -1;
	ans[px][py] = 0;
	node temp;
	temp.x = px, temp.y=py, temp.v = 0;
			
	bfs(temp);
	
	for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            printf("%-5d", ans[i][j]);
        }
        if(i < n) printf("\n");
    }
	
	return 0;
}

双向BFS

走迷宫


八数码难题


状压搜索

砝码称重


虫食算


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值