最佳运动员配对问题-婚姻搭配-最小重量机器设计问题-回溯法

回溯法练习集合

最佳运动员配对问题(就是婚姻搭配问题)

#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;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值