回溯法练习集合
最佳运动员配对问题(就是婚姻搭配问题)
#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;
const int maxn = 112;
int n;
int p[maxn][maxn], q[maxn][maxn], select[maxn];
//n对男女的婚姻搭配问题,求最大满意程度
//解空间:排列集 n!
int cw, maxV; //cw当钱满意程度,maxV最大满意诚度
int bestSelect[maxn];
void backTrack(int t) {
if (t > n) {
if(cw > maxV) {
memcpy(bestSelect, select, maxn);
maxV = cw;
}
}
else {
for (int i = t; i <= n; ++i) { //该第i个女生选了
cw += q[select[i]][t] * p[t][select[i]];
swap(select[i], select[t]); //之前这两句写反了,调试发现错的
backTrack(t + 1);
cw -= q[select[i]][t] * p[t][select[i]]; //回溯
swap(select[i], select[t]);
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
while(~scanf("%d", &n)) {
cw = maxV = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf("%d", &p[i][j]); //男方i对女方j的满意程度
}
select[i] = i;
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf("%d", &q[i][j]); //女方i对男方j的满意程度
}
}
backTrack(1);
printf("%d\n", maxV); //最大满意程度
// for (int i = 1; i <= n; ++i) {
// printf("%d\t%d\t%d\t%d\t%d\n", i , bestSelect[i], q[bestSelect[i]][i], p[i][bestSelect[i]], q[bestSelect[i]][i] * p[i][bestSelect[i]]);
// }
}
return 0;
}
/*
input.txt
3
10 2 3
2 3 4
3 4 5
2 2 2
3 5 3
4 5 1
output.txt
52
*/
#include <cstdio>
#include <cstring>
#include <climits>
const int maxn = 112;
int w[maxn][maxn], c[maxn][maxn];//w[i][j]从供应商j处购得器件i的重量,c[i][j]是相应的价格
int n, m, C;//器件数,厂家树,价格上限
//求价格不超过c的最小重量数,解空间:子集树,m^n 老师可能会说排列树
//每个器件都要选一个,故需选n个,价格c是一个剪枝约束,找最有要搜索检查所有可能性
//输出最小重量和么个器件的相应供应商
int cp, cw, minW;//cp已花费钱数,cw当前重量,minW选了n个器件的最小重量
int select[maxn], bestSelect[maxn];
void backTrack(int i) {
if (i > n) {
if (cw < minW) {
minW = cw;
memcpy(bestSelect, select, maxn);
}
}
else {
for (int j = 1; j <= m; ++j) { //区别于一般的选和不选,这里有m个替代物,所以说是子集树
if (cw + w[i][j] < minW && cp + c[i][j] <= C) {
cw += w[i][j];
cp += c[i][j];
select[i] = j;//第i个器件选的是第j个厂家,这个不用回溯,值会被覆盖
backTrack(i + 1);
cw -= w[i][j];
cp -= c[i][j];//[\笑cray],回溯
}
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
while(~scanf("%d%d%d", &n, &m, &C)) {
cp = cw = 0; //当前花费和当前重量
minW = INT_MAX;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &c[i][j]); //价格
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%d", &w[i][j]); //重量
}
}
backTrack(1); //从器件1的选择,搜索到器件n的选择
printf("%d\n%d", minW, bestSelect[1]);
for (int i = 2; i <= m; ++i) {
printf(" %d", bestSelect[i]);
}
puts("");
}
return 0;
}
/*
input.txt
3 3 4
1 2 3
3 2 1
2 2 2
1 2 3
3 2 1
2 2 2
output.txt
4
1 3 1
*/
子集和问题(选择恰好等于……)
//数据n稍微大点就容易超时,可以改用01背包
#include <stdio.h>
#include <string.h>
#define N 112
int n, c, ary[N], bestSelect[N], flag;
void backTrack(int i, int cw, int r, int select[]) {
if (i >= n || cw == c) {
if (cw == c) {
flag = 1;
memcpy(bestSelect, select, N);
}
}
else {
if (flag == 0 && cw + ary[i] <= c) {
select[i] = ary[i]; //我选择了你
backTrack(i + 1, cw + ary[i], r - ary[i], select);
}
else {
if (flag == 0 && cw + r >= c) {
backTrack(i + 1, cw, r, select);
}
}
}
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
while(~scanf("%d%d", &n, &c)) {
int i, sum = 0;
flag = 0;
int select[N] = { 0 };
for (i = 0; i < n; ++i) {
scanf("%d", ary + i);
sum += ary[i];
}
if (sum < c) {
puts("No Solution");
}
else {
backTrack(0, 0, sum, select);
if(flag == 0)
puts("No Solution");
else {
for (i = 0; i < n; ++i)
if(bestSelect[i] != 0) {
printf("%d", bestSelect[i]);
break;
}
for (++i; i < n; ++i)
if (bestSelect[i] != 0)
printf(" %d", bestSelect[i], select);
puts("");
}
}
}
return 0;
}
装载问题
//装载问题(装载总量不大时用01背包求解)
#include <stdio.h>
#include <string.h>
#define N 112
int bestVis[N], w[N]; //太多肯定超时
int c, n, bestw;
void backTrack(int i, int cw, int r, int vis[]) {
//物品t,当前装载量,剩余物品量
if(i >= n) {
if (cw > bestw)
bestw = cw;
memcpy(bestVis, vis, sizeof(int) * N);
}
else {
r -= w[i];
if (cw + w[i] <= c) {
cw += w[i];
vis[i] = 1;
backTrack(i + 1, cw, r, vis);
cw -= w[i]; //还原
vis[i] = 0;
}
if (cw + r > bestw)
backTrack(i + 1, cw, r, vis);
r += w[i]; //返回上层前,还原装载量
}
}
int main()
{
while(~scanf("%d%d", &c, &n) && (c | n)) {
int sum = 0;
bestw = 0;
int vis[112] = {0};
for (int i = 0; i < n; ++i) {
scanf("%d", w + i);
sum += w[i];
}
backTrack(0, 0, sum, vis);
printf("%d, (%d", bestw, bestVis[0]);
for (int i = 1; i < n; ++i)
printf(", %d", bestVis[i]);
puts(")");
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
string str;
while(cin >> str) {
int k;
cin >> k;
int cnt = str.length() - k; //cnt为最小数的位数
string ans;
string::iterator left = str.begin(), right = str.end() - cnt + 1, it;
while(cnt--) {
it = min_element(left, right);
ans.append(1, *it);
left = it + 1;
right++;
}
//删除前导0,第三个参数不用写it++,若有删除,it就指向新的字字母了
for (it = ans.begin(); it != ans.end() && *it == '0';)
ans.erase(it);
if (ans.length() == 0)
ans = "0";
cout << ans << endl;
}
return 0;
}