动态规划练习

搜索( d f s , b f s dfs, bfs dfs,bfs )

P1443 马的遍历

题目描述

有一个 n × m n \times m n×m 的棋盘,在某个点 ( x , y ) (x, y) (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。

输入格式

输入只有一行四个整数,分别为 n , m , x , y n, m, x, y n,m,x,y

输出格式

一个 n × m n \times m n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 − 1 -1 1)。

输入输出样例 #1

输入 #1

3 3 1 1

输出 #1

0    3    2    
3    -1   1    
2    1    4

说明/提示

数据规模与约定

对于全部的测试点,保证 1 ≤ x ≤ n ≤ 400 1 \leq x \leq n \leq 400 1xn400 1 ≤ y ≤ m ≤ 400 1 \leq y \leq m \leq 400 1ym400

b f s bfs bfs

一道 b f s bfs bfs 的模板题,先把马最先的位置压入队列,弹出后再压入所有马走一步能到的地方,如果之前已经到达过了这个地方就不重复压入。

最后注意有五格场宽。

#include<bits/stdc++.h>
using namespace std;
int n, m;
int x, y;
int a[402][402];
int xx[8] = { -1,-2,-2,-1,1,2,2,1 };
int yy[8] = { 2,1,-1,-2,-2,-1,1,2 };
struct node {
	int x, y;
};
queue<node>q;
int main() {
	cin >> n >> m >> x >> y;
	memset(a, -1, sizeof(a));
	a[x][y] = 0;
	q.push({ x,y });
	while (!q.empty()) {
		int x1 = q.front().x;
		int y1 = q.front().y;
		q.pop();
		for (int i = 0; i < 8; i++) {
			int x2 = x1 + xx[i];
			int y2 = y1 + yy[i];
			if (x2 > 0 && x2 <= n && y2 > 0 && y2 <= m && a[x2][y2] == -1) {
				a[x2][y2] = a[x1][y1] + 1;
				q.push({ x2,y2 });
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cout << setw(5) << a[i][j];
		}
		cout << endl;
	}
	return 0;
}

P2895 [USACO08FEB] Meteor Shower S

题目描述

贝茜听说一场特别的流星雨即将到来:这些流星会撞向地球,并摧毁它们所撞击的任何东西。她为自己的安全感到焦虑,发誓要找到一个安全的地方(一个永远不会被流星摧毁的地方)。

如果将牧场放入一个直角坐标系中,贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。

根据预报,一共有 M M M 颗流星 ( 1 ≤ M ≤ 50 , 000 ) (1\leq M\leq 50,000) (1M50,000) 会坠落在农场上,其中第 i i i 颗流星会在时刻 T i T_i Ti 0 ≤ T i ≤ 1000 0 \leq T _ i \leq 1000 0Ti1000)砸在坐标为 ( X i , Y i ) ( 0 ≤ X i ≤ 300 (X_i,Y_i)(0\leq X_i\leq 300 (Xi,Yi)(0Xi300 0 ≤ Y i ≤ 300 ) 0\leq Y_i\leq 300) 0Yi300) 的格子里。流星的力量会将它所在的格子,以及周围 4 4 4 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。

贝茜在时刻 0 0 0 开始行动,她只能在会在横纵坐标 X , Y ≥ 0 X,Y\ge 0 X,Y0 的区域中,平行于坐标轴行动,每 1 1 1 个时刻中,她能移动到相邻的(一般是 4 4 4 个)格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 t t t 被流星撞击或烧焦,那么贝茜只能在 t t t 之前的时刻在这个格子里出现。 贝茜一开始在 ( 0 , 0 ) (0,0) (0,0)

请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 − 1 −1 1

输入格式

M + 1 M+1 M+1 行,第 1 1 1 行输入一个整数 M M M,接下来的 M M M 行每行输入三个整数分别为 X i , Y i , T i X_i, Y_i, T_i Xi,Yi,Ti

输出格式

贝茜到达安全地点所需的最短时间,如果不可能,则为 − 1 -1 1

输入输出样例 #1

输入 #1

4
0 0 2
2 1 2
1 1 2
0 3 5

输出 #1

5

也是一道 b f s bfs bfs ,每次移动时检查一下下一步会不会被陨石砸到,除此之外就是一道板子题

#include<bits/stdc++.h>
using namespace std;
int a[302][302];
int b[302][302];
int n;
struct drop {
	int x, y, t;
}m[50005];
struct node {
	int x, y, t;
};
int xb[4] = { -1, 0, 1, 0 };
int yb[4] = { 0, -1, 0, 1 };
int t1 = 0;
queue<node>q;
int main() {
	cin >> n;
	memset(a, -1, sizeof(a));
	for (int i = 0; i < n; i++) {
		cin >> m[i].x >> m[i].y >> m[i].t;
	}
	for (int i = 0; i < n; i++) {
		int xx = m[i].x;
		int yy = m[i].y;
		int tt = m[i].t;
		if (a[xx][yy] == -1)a[xx][yy] = tt;
		else a[xx][yy] = min(a[xx][yy], tt);
		for (int j = 0; j < 4; j++) {
			int xxx = xx + xb[j];
			int yyy = yy + yb[j];
			if (xxx >= 0 && yyy >= 0){
				if (a[xxx][yyy] == -1)a[xxx][yyy] = tt;
				else a[xxx][yyy] = min(a[xxx][yyy], tt);
			}
		}
	}
	q.push({ 0, 0 ,0 });
	b[0][0] = 1;
	while (!q.empty()) {
		int x2 = q.front().x;
		int y2 = q.front().y;
		int t2 = q.front().t;
		q.pop();
		if (a[x2][y2] == -1) {
			cout << t2;
			return 0;
		}
		for (int i = 0; i < 4; i++) {
			int x3 = x2 + xb[i];
			int y3 = y2 + yb[i];
			int t3 = t2 + 1;
			if (x3 >= 0 && y3 >= 0 && (t3 < a[x3][y3] || a[x3][y3] == -1) && !b[x3][y3]) {
				q.push({ x3,y3,t3 });
				b[x3][y3] = t3;
			}
		}
	}
	cout << -1;
	return 0;
}

P1036 [NOIP 2002 普及组] 选数

题目描述

已知 n n n 个整数 x 1 , x 2 , ⋯   , x n x_1,x_2,\cdots,x_n x1,x2,,xn,以及 1 1 1 个整数 k k k k < n k<n k<n)。从 n n n 个整数中任选 k k k 个整数相加,可分别得到一系列的和。例如当 n = 4 n=4 n=4 k = 3 k=3 k=3 4 4 4 个整数分别为 3 , 7 , 12 , 19 3,7,12,19 3,7,12,19 时,可得全部的组合与它们的和为:

3 + 7 + 12 = 22 3+7+12=22 3+7+12=22

3 + 7 + 19 = 29 3+7+19=29 3+7+19=29

7 + 12 + 19 = 38 7+12+19=38 7+12+19=38

3 + 12 + 19 = 34 3+12+19=34 3+12+19=34

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数: 3 + 7 + 19 = 29 3+7+19=29 3+7+19=29

输入格式

第一行两个空格隔开的整数 n , k n,k n,k 1 ≤ n ≤ 20 1 \le n \le 20 1n20 k < n k<n k<n)。

第二行 n n n 个整数,分别为 x 1 , x 2 , ⋯   , x n x_1,x_2,\cdots,x_n x1,x2,,xn 1 ≤ x i ≤ 5 × 1 0 6 1 \le x_i \le 5\times 10^6 1xi5×106)。

输出格式

输出一个整数,表示种类数。

输入输出样例 #1

输入 #1

4 3
3 7 12 19

输出 #1

1

说明/提示

【题目来源】

NOIP 2002 普及组第二题

d f s dfs dfs 选够数后检查和是否是素数

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e8 + 10;
int ans = 0;
int b[22];
int a[22];
int n, k;
int sum = 0;
stack<int>s;
bool check(int x) {
	for (int i = 2; i * i < x; i++) {
		if (x % i == 0)return false;
	}
	return true;
}
void dfs(int num, int x) {
	if (num == k) {
		if (check(sum))ans++;
		return;
	}

	for (int i = x + 1; i <= n; i++) {
		b[i] = 1;
		sum += a[i];
		dfs(num + 1, i);
		b[i] = 0;
		sum -= a[i];
	}
}
int main() {
	cin >> n >> k;
	for (int i = 1; i <= n; i++)cin >> a[i];
	dfs(0, 0);
	cout << ans;
	return 0;
}

P2036 [COCI 2008/2009 #2] PERKET

题目描述

Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 n n n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s s s 和苦度 b b b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。

众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。

另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。

输入格式

第一行一个整数 n n n,表示可供选用的食材种类数。

接下来 n n n 行,每行 2 2 2 个整数 s i s_i si b i b_i bi,表示第 i i i 种食材的酸度和苦度。

输出格式

一行一个整数,表示可能的总酸度和总苦度的最小绝对差。

输入输出样例 #1

输入 #1

1
3 10

输出 #1

7

输入输出样例 #2

输入 #2

2
3 8
5 8

输出 #2

1

输入输出样例 #3

输入 #3

4
1 7
2 6
3 8
4 9

输出 #3

1

说明/提示

数据规模与约定

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 10 1 \leq n \leq 10 1n10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1 × 1 0 9 1 \times 10^9 1×109,酸度和苦度不同时为 1 1 1 0 0 0

d f s dfs dfs 数很大我开的 l o n g long long l o n g long long

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n;
struct food {
	ll si, bi;
}f[10];
ll abs1(ll a) {
	return a > 0 ? a : -a;
}
ll min(ll a, ll b) {
	return a < b ? a : b;
}
ll s = 1;
ll b = 0;
ll minn;
void dfs(int x){
	for (int i = x + 1; i <= n; i++) {
		s *= f[i].si;
		b += f[i].bi;
		minn = min(abs(s - b), minn);
		dfs(i);
		s /= f[i].si;
		b -= f[i].bi;
	}
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> f[i].si >> f[i].bi;
	minn = abs1(f[1].si - f[1].bi);
	dfs(0);
	cout << minn;
	return 0;
}

P1605 迷宫

题目描述

给定一个 N × M N \times M N×M 方格的迷宫,迷宫里有 T T T 处障碍,障碍处不可通过。

在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。

输入格式

第一行为三个正整数 N , M , T N,M,T N,M,T,分别表示迷宫的长宽和障碍总数。

第二行为四个正整数 S X , S Y , F X , F Y SX,SY,FX,FY SX,SY,FX,FY S X , S Y SX,SY SX,SY 代表起点坐标, F X , F Y FX,FY FX,FY 代表终点坐标。

接下来 T T T 行,每行两个正整数,表示障碍点的坐标。

输出格式

输出从起点坐标到终点坐标的方案总数。

输入输出样例 #1

输入 #1

2 2 1
1 1 2 2
1 2

输出 #1

1

说明/提示

对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 5 1 \le N,M \le 5 1N,M5 1 ≤ T ≤ 10 1 \le T \le 10 1T10 1 ≤ S X , F X ≤ n 1 \le SX,FX \le n 1SX,FXn 1 ≤ S Y , F Y ≤ m 1 \le SY,FY \le m 1SY,FYm

d f s dfs dfs

#include<bits/stdc++.h>
using namespace std;
int n, m, t;
int sx, sy, fx, fy;
int ans;
int xx[4] = { -1,0,1,0 };
int yy[4] = { 0,-1,0,1 };
int a[7][7];
int b[7][7];
void dfs(int x1, int y1) {
	if (x1 == fx && y1 == fy) {
		ans++;
		return;
	}
	for (int i = 0; i < 4; i++) {
		int x2 = x1 + xx[i];
		int y2 = y1 + yy[i];
		if (x2 >= 1 && x2 <= n && y2 >= 1 && y2 <= m && !a[x2][y2] && !b[x2][y2]) {
			b[x2][y2] = 1;
			dfs(x2, y2);
			b[x2][y2] = 0;
		}
	}
}
int main() {
	cin >> n >> m >> t;
	cin >> sx >> sy >> fx >> fy;
	for (int i = 0; i < t; i++) {
		int p, q;
		cin >> p >> q;
		a[p][q] = 1;
	}
	b[sx][sy] = 1;
	dfs(sx, sy);
	cout << ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值