递归与递推

  1. 由数据范围反推算法复杂度以及算法内容

题目:(递归实现指数型枚举)从 1∼n这 n个整数中随机选取任意多个,输出所有可能的选择方案。(时间复杂度:n*(2^n) )

数据范围:1≤n≤15

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 16; //多开1

int n;
int st[N]; // 状态,记录每个位置当前的状态:0表示还没考虑,1表示选它,2表示不选它

void dfs(int u)
{
if (u > n)
{
for (int i = 1; i <= n; i ++ )
if (st[i] == 1)
printf("%d ", i);
printf("\n");
return;
}

st[u] = 2;
dfs(u + 1); // 第一个分支:不选
st[u] = 0; // 恢复现场

st[u] = 1;
dfs(u + 1); // 第二个分支:选
st[u] = 0;
}

int main()
{
cin >> n;

dfs(1);

return 0;
}

题目:(递归实现排列型枚举)把 1∼n这 n个整数排成一行后随机打乱顺序,输出所有可能的次序。(时间复杂度:n*n! )

数据范围:1≤n≤9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10;

int n;
int state[N]; // 0 表示还没放数,1~n表示放了哪个数
bool used[N]; // true表示用过,false表示还未用过

void dfs(int u)
{
if (u > n) // 边界
{
for (int i = 1; i <= n; i ++ ) printf("%d ", state[i]); // 打印方案
puts("");

return;
}

// 依次枚举每个分支,即当前位置可以填哪些数
for (int i = 1; i <= n; i ++ )
if (!used[i])
{
state[u] = i;
used[i] = true;
dfs(u + 1);

// 恢复现场
state[u] = 0;
used[i] = false;
}
}

int main()
{
scanf("%d", &n);

dfs(1);

return 0;
}


题目:(递归实现组合型枚举)从 1∼n这 n个整数中随机选出 m个,输出所有可能的选择方案。

数据范围:n>0 ,0≤m≤n ,n+(n−m)≤25

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 30;

int n, m;
int way[N];

void dfs(int u, int start)
{
if (u + n - start < m) return; // 剪枝
if (u == m + 1)
{
for (int i = 1; i <= m; i ++ ) printf("%d ", way[i]);
puts("");
return;
}

for (int i = start; i <= n; i ++ )
{
way[u] = i;
dfs(u + 1, i + 1);
way[u] = 0; // 恢复现场
}
}

int main()
{
scanf("%d%d", &n, &m);

dfs(1, 1);

return 0;
}

题目:(带分数)

数据范围:1≤N<10^6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10;

int n;
bool st[N], backup[N];
int ans;

bool check(int a, int c)
{
long long b = n * (long long)c - a * c;

if (!a || !b || !c) return false;

memcpy(backup, st, sizeof st);
while (b)
{
int x = b % 10; // 取个位
b /= 10; // 个位删掉
if (!x || backup[x]) return false;
backup[x] = true;
}

for (int i = 1; i <= 9; i ++ )
if (!backup[i])
return false;

return true;
}

void dfs_c(int u, int a, int c)
{
if (u > 9) return;

if (check(a, c)) ans ++ ;

for (int i = 1; i <= 9; i ++ )
if (!st[i])
{
st[i] = true;
dfs_c(u + 1, a, c * 10 + i);
st[i] = false;
}
}

void dfs_a(int u, int a)
{
if (a >= n) return;
if (a) dfs_c(u, a, 0);

for (int i = 1; i <= 9; i ++ )
if (!st[i])
{
st[i] = true;
dfs_a(u + 1, a * 10 + i);
st[i] = false;
}
}

int main()
{
cin >> n;

dfs_a(0, 0);

cout << ans << endl;

return 0;
}

题目:(简单斐波那契)

以下数列 0 1 1 2 3 5 8 13 21 ... 被称为斐波纳契数列。

这个数列从第 33 项开始,每一项都等于前两项之和。

输入一个整数 N,请你输出这个序列的前 N项。

数据范围:0<N<46

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
int a = 0, b = 1;
int n;
cin >> n;

for (int i = 0; i < n; i ++ )
{
cout << a << ' ';
int c = a + b;
a = b, b = c;
}

cout << endl;

return 0;
}

题目:(费解的开关)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 6;

char g[N][N], backup[N][N];
int dx[5] = {-1, 0, 1, 0, 0}, dy[5] = {0, 1, 0, -1, 0};

void turn(int x, int y)
{
for (int i = 0; i < 5; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= 5 || b < 0 || b >= 5) continue; // 在边界外,直接忽略即可
g[a][b] ^= 1;
}
}

int main()
{
int T;
cin >> T;
while (T -- )
{
for (int i = 0; i < 5; i ++ ) cin >> g[i];

int res = 10;
for (int op = 0; op < 32; op ++ )
{
memcpy(backup, g, sizeof g);
int step = 0;
for (int i = 0; i < 5; i ++ )
if (op >> i & 1)
{
step ++ ;
turn(0, 4 - i);
}

for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 5; j ++ )
if (g[i][j] == '0')
{
step ++ ;
turn(i + 1, j);
}

bool dark = false;
for (int i = 0; i < 5; i ++ )
if (g[4][i] == '0')
{
dark = true;
break;
}

if (!dark) res = min(res, step);
memcpy(g, backup, sizeof g);
}

if (res > 6) res = -1;

cout << res << endl;
}

return 0;
}

题目:(翻硬币)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n;
char start[N], aim[N];

void turn(int i)
{
if (start[i] == '*') start[i] = 'o';
else start[i] = '*';
}

int main()
{
cin >> start >> aim;
n = strlen(start);

int res = 0;
for (int i = 0; i < n - 1; i ++ )
if (start[i] != aim[i])
{
turn(i), turn(i + 1);
res ++ ;
}

cout << res << endl;
return 0;
}

题目:(飞行员兄弟)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 5;

char g[N][N], backup[N][N];

int get(int x, int y)
{
return x * 4 + y;
}

void turn_one(int x, int y)
{
if (g[x][y] == '+') g[x][y] = '-';
else g[x][y] = '+';
}

void turn_all(int x, int y)
{
for (int i = 0; i < 4; i ++ )
{
turn_one(x, i);
turn_one(i, y);
}

turn_one(x, y);
}

int main()
{
for (int i = 0; i < 4; i ++ ) cin >> g[i];

vector<PII> res;
for (int op = 0; op < 1 << 16; op ++ )
{
vector<PII> temp;
memcpy(backup, g, sizeof g); // 备份

// 进行操作
for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 4; j ++ )
if (op >> get(i, j) & 1)
{
temp.push_back({i, j});
turn_all(i, j);
}

// 判断所有灯泡是否全亮
bool has_closed = false;
for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 4; j ++ )
if (g[i][j] == '+')
has_closed = true;

if (has_closed == false)
{
if (res.empty() || res.size() > temp.size()) res = temp;
}

memcpy(g, backup, sizeof g); // 还原
}

cout << res.size() << endl;
for (auto op : res) cout << op.x + 1 << ' ' << op.y + 1 << endl;

return 0;
}