目录
1256:献给阿尔吉侬的花束
1253:抓住那头牛
1360:奇怪的电梯(lift)
1199:全排列
1317:【例5.2】组合的输出
【题目描述】
阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。
迷宫用一个R×C的字符矩阵来表示。字符S表示阿尔吉侬所在的位置,字符E表示奶酪所在的位置,字符#表示墙壁,字符.表示可以通行。阿尔吉侬在1个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。
【输入】
第一行是一个正整数T(1 ≤ T ≤ 10),表示一共有T组数据。
每一组数据的第一行包含了两个用空格分开的正整数R和C(2 ≤ R, C ≤ 200),表示地图是一个R×C的矩阵。
接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个S和E。
【输出】
对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。
【输入样例】
3 3 4 .S.. ###. ..E. 3 4 .S.. .E.. .... 3 4 .S.. #### ..E.
【输出样例】
5 1 oop!
#include
#include
using namespace std;
const int N = 2e2 + 10;
char g[N][N];
bool vis[N][N];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
int t;
int n,m,sx, sy, tx, ty;
int ans;
struct point { int x; int y; int depth; };
void bfs(point s)
{
queueq;
q.push(s); vis[s.x][s.y] = 1;
while (!q.empty())
{
point cur = q.front(); q.pop();
if (cur.x == tx && cur.y == ty)
{
ans = cur.depth-1;
return;
}
for (int i = 0; i < 4; i++)
{
int bx = cur.x + dx[i], by = cur.y + dy[i];
if (bx<1 || bx> n || by<1 || by>m) continue;
if (vis[bx][by]) continue;
if (g[bx][by]=='#') continue;
vis[bx][by] = 1;
q.push({ bx, by,cur.depth+1 });
}
}
}
int main()
{
cin >> t;
while (t--)
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> g[i][j];
if (g[i][j] == 'S')sx = i, sy = j;
if (g[i][j] == 'E')tx = i, ty = j;
}
}
ans = -1;
memset(vis, 0, sizeof vis);
bfs({ sx, sy,1 });
if (ans == -1)
cout << "oop!" << endl;
else
cout << ans << endl;
}
return 0;
}
【题目描述】
农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0≤N≤100000)�(0≤�≤100000),牛位于点K(0≤K≤100000)�(0≤�≤100000)。农夫有两种移动方式:
1、从X�移动到X−1�−1或X+1�+1,每次移动花费一分钟
2、从X移动到2×X2×�,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?
【输入】
两个整数,N�和K�。
【输出】
一个整数,农夫抓到牛所要花费的最小分钟数。
【输入样例】
5 17
【输出样例】
4
#include
#include
using namespace std;
const int N = 1e5 + 10;
char g[N];
bool vis[N];
int s, t, b;
int ans;
struct point { int x; int depth; };
int d[] = { 1,-1,2 };
void bfs(point p)
{
queueq;
q.push(p); vis[p.x] = 1;
while (!q.empty())
{
point cur = q.front(); q.pop();
if (cur.x == t)
{
ans = cur.depth-1;
return;
}
for (int i = 0; i < 3; i++)
{
//特判*2的路径
if(i<2) b = cur.x + d[i];
else b = cur.x *d[i];
if (b<0 || b>1e5 ) continue;
if (vis[b]) continue;
vis[b] = 1;
q.push({ b,cur.depth+1 });
}
}
}
int main()
{
cin >> s >> t;
bfs({ s,1 });
cout << ans;
return 0;
}
【题目描述】
大楼的每一层楼都可以停电梯,而且第i层楼(1≤i≤N)(1≤�≤�)上有一个数字Ki(0≤=Ki≤=N)��(0≤=��≤=�)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:
3 3 1 2 5
代表了Ki(K1=3,K2=3,……)��(�1=3,�2=3,……),从一楼开始。在一楼,按“上”可以到44楼,按“下”是不起作用的,因为没有−2−2楼。那么,从A�楼到B�楼至少要按几次按钮呢?【输入】
共有二行,第一行为三个用空格隔开的正整数,表示N,A,B(1≤N≤200,1≤A,B≤N)�,�,�(1≤�≤200,1≤�,�≤�),第二行为N�个用空格隔开的正整数,表示Ki��。
【输出】
一行,即最少按键次数,若无法到达,则输出−1−1。
【输入样例】
5 1 5 3 3 1 2 5
【输出样例】
3
#include
#include
using namespace std;
const int N = 2e2 + 10;
char g[N];
bool vis[N];
int n, a, b;
int ans=-1;
struct point { int x; int depth; };
int a1[N];
void bfs(point p)
{
queueq;
q.push(p); vis[p.x] = 1;
while (!q.empty())
{
point cur = q.front(); q.pop();
if (cur.x == b)
{
ans = cur.depth-1;
return;
}
//向前向后移动分开判定
int nxt1 = cur.x + a1[cur.x], nxt2 = cur.x - a1[cur.x];
if (nxt1 >= 1 && nxt1 <= n && !vis[nxt1]) {
vis[nxt1] = 1;
q.push({ nxt1,cur.depth + 1 });
}
if (nxt2 >= 1 && nxt2 <= n && !vis[nxt2]) {
vis[nxt2] = 1;
q.push({ nxt2,cur.depth + 1 });
}
}
}
int main()
{
cin >> n >> a >> b;
for (int i = 1; i <= n; i++)
cin >> a1[i];//相当于方向数组
bfs({ a,1 });
cout << ans;
return 0;
}
|
【题目描述】
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你用递归的方法输出所有组合。
例如n=5,r=3,所有组合为:
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
【输入】
一行两个自然数n、r(1
【输出】
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
【输入样例】
5 3
【输出样例】
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
#include
using namespace std;
string s;
const int N = 1e2 + 10;
bool vis[N];
char cnt[N];
//搜索与回溯算法的模板
void dfs(int depth) {
//5.终止条件
if (depth > s.size()) {
//打印原则:搜多少打多少
for (int i = 1; i < depth; i++) cout << cnt[i];
cout << endl;
return;
}
//1.枚举方案
for (int i = 0; i < s.size(); i++) {
//2.标记-防止重复搜索
if (!vis[i]) {
//3.搜索
vis[i] = 1;
cnt[depth] = s[i];
dfs(depth + 1);
//4.回溯
vis[i] = 0;
}
}
}
int main() {
cin >> s;
dfs(1);
return 0;
}
#include
using namespace std;
//n选r问题的组合
int n,r;
const int N = 1e2 + 10;
bool vis[N];
int cnt[N];
//搜索与回溯算法的组合模板
void dfs(int depth) {
//5.终止条件
if (depth > r) {
//打印原则:搜多少打多少
for (int i = 1; i < depth; i++) printf("%3d",cnt[i]);
cout << endl;
return;
}
//1.枚举方案
for (int i = 1; i <= n;i++) {
//2.标记-防止重复搜索
if (!vis[i]&&i>cnt[depth-1]) {//保证无重复,也就是字典序升序,当前搜的比上一层大
//3.搜索
vis[i] = 1;
cnt[depth] = i;
dfs(depth + 1);
//4.回溯
vis[i] = 0;
}
}
}
int main() {
cin >> n >> r;//从字符串s中选r个进行全排列
dfs(1);
return 0;
}