例题1:01背包
题目:有 n n n件物品,每件物品的重量为 w [ i ] w[i] w[i],价值为 c [ i ] c[i] c[i]。现在需要选出若干件物品放入一个容器为 V V V的背包中,使得在选入背包的物品重量和不超过容量为 V V V的前提下,让背包中物品的价值之和最大,求最大价值。 ( 1 < = n < = 20 ) (1<=n<=20) (1<=n<=20)
如输入数据:
5 8 //5件物品,背包容量为8
3 5 1 2 2 //重量分别为3 5 1 2 2
4 5 2 1 3 //价值分别为4 5 2 1 3
输出结果
10
(注:其实这是一道01背包问题,可以用动态规划快速求解,但这里使用深度优先搜索。)
#include <iostream>
using namespace std;
const int maxn = 30;
int n, V, maxValue = 0; //物品的件数,背包容量V,最大价值maxValue
int w[maxn], c[maxn]; //w[i]为每件物品的重量,c[i]为每件物品的价值
//index为当前处理的物品编号
//sumW和sumC分别为当前的总重量和总价值
void dfs(int index,int sumW, int sumC) {
if (index == n) { //已经完成对n件物品的选择(死胡同)
if (sumW<=V && sumC>maxValue) {
maxValue = sumC; //不超过背包容量时更新最大价值maxValue
}
return;//一定别忘了return!
}
//岔路口
dfs(index+1,sumW, sumC); //不选第index件物品
dfs(index+1,sumW +w[index], sumC +c[index] ); //选第index件物品
}
int main() {
cin >> n >> V;
for (int i = 0; i < n; i++) {
cin >> w[i];
}
for (int i = 0; i < n; i++) {
cin >> c[i];
}
dfs(0, 0, 0);
cout << maxValue;
return 0;
}
剪枝优化:(剪枝就是艺术)
#include <iostream>
using namespace std;
const int maxn = 30;
int n, V, maxValue = 0; //物品的件数,背包容量V,最大价值maxValue
int w[maxn], c[maxn]; //w[i]为每件物品的重量,c[i]为每件物品的价值
//index为当前处理的物品编号
//sumW和sumC分别为当前的总重量和总价值
void dfs(int index,int sumW, int sumC) {
if (index == n) { //已经完成对n件物品的选择(死胡同)
if (sumW<=V && sumC>maxValue) {
maxValue = sumC; //不超过背包容量时更新最大价值maxValue
}
return;//一定别忘了return!
}
//岔路口
dfs(index+1,sumW, sumC); //不选第index件物品
if(sumW<V) //剪枝
dfs(index+1,sumW +w[index], sumC +c[index] ); //选第index件物品
}
int main() {
cin >> n >> V;
for (int i = 0; i < n; i++) {
cin >> w[i];
}
for (int i = 0; i < n; i++) {
cin >> c[i];
}
dfs(0, 0, 0);
cout << maxValue;
return 0;
}
例题2:N个数选K个数组方案
题目:给定N个整数(可能有负数),从中选择K个数,使得这K个数之和恰好等于一个给定的整数X,如果有多种方案,选择他们中元素平方和最大的一个。数据保证这样的方案唯一。例如,从4个整数{2,3,3,4}中选择2个数,使它们的和为6,显然有两种方案{2,4}与{3,3},其中平方和最大的方案为{2,4}。
输入描述
4 2 6 //依次为题意中的N,K,X
2 3 3 4 //N个整数数值
输出
2 4
与上面计算总价值不同,这道题要求输出选择的数。
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 10010;
//序列A中n个数选k个数使得和为x,最大平方和为maxSumSqu
int n, k, x, maxSumSqu = -1, A[maxn];
//temp存放临时方案,ans存放平方和最大的方案
vector<int>temp, ans;
void dfs(int index, int nowK, int sum, int sumSqu) {
if (index == n ) {
return;
}
if (nowK == k && sum == x) {
if (sumSqu > maxSumSqu) {
maxSumSqu = sumSqu;
ans = temp;
}
return;
}
temp.push_back(A[index]);
dfs(index+1,nowK+1,sum+A[index],sumSqu+A[index]*A[index]);
temp.pop_back();
dfs(index+1, nowK, sum, sumSqu);
}
int main() {
cin >> n >> k >> x;
for (int i = 0; i < n; i++) {
cin >> A[i];
}
dfs(0, 0, 0,0);
for (int i : ans)
cout << i << " ";
cout << endl;
return 0;
}
作业习题1:问题 A: 【递归入门】全排列
#include <iostream>
using namespace std;
const int max = 10010;
int n, vis[max], ans[max];
void display() {
for (int i = 0; i<n - 1; i++)
cout << ans[i] << " ";
cout << ans[n - 1] << endl;
}
void dfs(int index) {
if (index == n) {//判断边界
display();
return;
}
for (int j = 1; j <= n; j++) {//尝试每一种可能
if (vis[j] == 0) {//满足check条件
ans[index] = j;//记录
vis[j] = 1;//标记
dfs(index + 1);//继续搜索
vis[j] = 0;//恢复初始状态(回溯的时候要用到)
}
}
}
int main() {
while (cin >> n) {
memset(vis, 0, sizeof(vis));//初始化
memset(ans, 0, sizeof(ans));//初始化
dfs(0);
}
return 0;
}
作业习题2:问题 B: 【递归入门】组合的输出
#include <iostream>
using namespace std;
const int max = 10010;
int n,r,vis[max], ans[max];
void display() {
for (int i = 1; i<=r ; i++)
cout << ans[i] << " ";
cout << endl;
}
void dfs(int index) {
if (index == r+1) {//判断边界
display();
return;
}
for (int j =1; j <= n; j++) {//尝试每一种可能 (如果index从0开始,-1后数组越界)
if (vis[j] == 0 && j>=ans[index-1]) {//满足check条件
ans[index] = j;//记录
vis[j] = 1;//标记
dfs(index + 1);//继续搜索
vis[j] = 0;//恢复初始状态(回溯的时候要用到)
}
}
}
int main() {
while (cin >> n>>r) {
memset(vis, 0, sizeof(vis));
memset(vis, 0, sizeof(ans));
ans[0] = 1;//这里需要赋值
dfs(1);//注意这里是从1开始,因此边界判断也要+1
}
return 0;
}
作业习题3:问题 C: 【递归入门】组合+判断素数
#include <iostream>
using namespace std;
const int Max = 10010;
int n, k, cnt, a[Max], vis[Max], ans[Max];
bool sum_is_prime(int *p) {
int sum = 0;
for (int i = 1; i <= k; i++) {
sum += ans[i];
}
for (int j = 2; j < sum; j++) {
if (sum%j == 0)
return false;
}
return true;
}
void dfs(int index) {
if (index == k + 1) {//判断边界
if (sum_is_prime(ans))
cnt++;
return;
}
for (int j = 1; j <= n; j++) {//尝试每一种可能
if (vis[a[j]] == 0 && a[j] >= ans[index - 1]) {//满足check条件
ans[index] = a[j];//记录
vis[a[j]] = 1;//标记
dfs(index + 1);//继续搜索
vis[a[j]] = 0;//恢复初始状态(回溯的时候要用到)
}
}
}
int main(){
while (cin >> n >> k) {
cnt = 0;
memset(vis, 0, sizeof(vis));
memset(vis, 0, sizeof(ans));
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
ans[0] = a[1];
dfs(1);
cout << cnt << endl;
}
return 0;
}
作业习题4:问题 D: 【递归入门】n皇后 问题(原始的8皇后问题)
问题 D: 【递归入门】n皇后 问题(原始的8皇后问题)
#include <iostream>
#include <vector>
using namespace std;
vector<pair<int, int>>temp(0);
int n;
bool find(pair<int,int>p) {
for (auto a : temp) {
if (a.first == p.first || a.second == p.second || a.first + a.second == p.first + p.second || a.first - a.second == p.first - p.second)
return true;
}
return false;
}
void display() {
for (auto i:temp)
cout <<i.second<< " ";
cout << endl;
}
void dfs(int row,int col) {
if (row == n + 1 ) {//判断边界
display();
return;
}
for (int i = 1; i <= n; i++) {
if (!find({row,i})) {
temp.push_back({ row,i });
dfs(row + 1, 1);
temp.pop_back();
}
}
}
int main() {
while (cin >> n) {
dfs(1,1);
}
return 0;
}
作业习题5:问题 E: 【递归入门】出栈序列统计
#include <iostream>
#include <stack>
using namespace std;
int cnt, n;
void dfs(int in, int out) {//参数in表示已经入栈的元素个数,out表示在栈外,即还未入栈的元素
if (out == 0) {
cnt++;
return;
}
if (in == 0) {
dfs(in + 1, out - 1);//当栈内无元素时,只能入栈
}
if(in>=1 && out>=1){//栈内,栈外都有元素
dfs(in + 1, out - 1);//入栈
dfs(in - 1, out);//出栈
}
}
int main() {
while (cin >> n) {
cnt = 0;
dfs(0, n);//已入栈元素为0,还未入栈的元素为n
cout << cnt << endl;
}
}
作业习题6:问题 F: 【递归入门】走迷宫
#include <iostream>
#include <vector>
using namespace std;
const int Max = 10010;
int n, m, maze[Max][Max];
int x_in, y_in, x_out, y_out;
vector<pair<int, int>>ans(0);
bool find(pair<int, int>p) {
for (auto a : ans) {
if (a.first == p.first && a.second == p.second) {
return true;
}
}
return false;
}
void display() {
for (auto a : ans)
cout << "(" << a.first << "," << a.second << ")" << "->";
cout << "(" << x_out << "," << y_out << ")" << endl;
}
void dfs(int x, int y) {
if (x == x_out && y == y_out) {
display();
return;
}
if (maze[x][y - 1] == 1) {
maze[x][y - 1] = 0;
ans.push_back({ x,y - 1 });
dfs(x, y - 1);
maze[x][y - 1] = 1;
ans.pop_back();
}
if (maze[x - 1][y] == 1) {
maze[x - 1][y] = 0;
ans.push_back({ x - 1,y });
dfs(x - 1, y);
maze[x - 1][y] = 1;
ans.pop_back();
}
if (maze[x][y + 1] == 1) {
maze[x][y + 1] = 0;
ans.push_back({ x,y + 1 });
dfs(x, y + 1);
maze[x][y + 1] = 1;
ans.pop_back();
}
if (maze[x + 1][y] == 1) {
maze[x + 1][y] = 0;
ans.push_back({ x + 1,y });
dfs(x + 1, y);
maze[x + 1][y] = 1;
ans.pop_back();
}
}
int main() {
while (cin >> n >> m) {
memset(maze, 0, sizeof(maze));//初始化
ans.clear();//初始化
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
cin >> maze[i][j];
}
cin >> x_in >> y_in >> x_out >> y_out;
ans.push_back({ x_in,y_in });
maze[x_in][y_in] = 0;
dfs(x_in, y_in);
}
return 0;
}
最后,如果有问题欢迎留言指出。