算法_回溯(最佳调度问题、八皇后问题、0-1背包、整数拆分、666、工作分配问题)

算法_回溯

最佳调度问题

假设有n(n<=20)个任务由k(k<=20)个可并行工作的机器完成。完成任务i需要的时间为ti。 试设计一个算法,对任意给定的整数n和k,以及完成任务i 需要的时间为ti ,i=1~n。计算完成这n个任务的最佳调度,使得完成全部任务的时间最早。

输入格式:
输入数据的第一行有2 个正整数n和k。第2 行的n个正整数是完成n个任务需要的时间。

输出格式:
将计算出的完成全部任务的最早时间输出到屏幕。

输入样例:
在这里给出一组输入。例如:

7 3
2 14 4 16 6 5 3

输出样例:
在这里给出相应的输出。例如:

17

代码:

#include <iostream>
using namespace std;
int n,k,a[20],b[20],Min = 1000000000;
void s(int x)
{
    if (x == n)
        {
            int Max = b[0]; 
            for (int i = 1;i <= k;i++)
                if (b[i] > Max)
                    Max = b[i];
            if (Max < Min) 
                Min = Max;
            return; 
        }
    for (int i = 0;i < k;i++)
        {
            if (b[i] + a[x] > Min)
				continue;
            b[i] += a[x]; 
            s(x+1);
            b[i] -= a[x]; 
        }
}
int main()
{
	int i;
    cin>>n>>k;
    for (i = 0; i < n;i++)
        cin>>a[i];
    for (i = 0;i < k;i++) 
        b[i] = 0;
    s(0);
   cout<<Min<<endl;
    return 0;
}

在这里插入图片描述

八皇后问题

在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。例如:

题图.jpg

现在我们把棋盘扩展到 n×n 的棋盘上摆放 n 个皇后,请问该怎么摆?

请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两个字符之间空一格)。

输入格式
正整数 n(n>0)

输出格式
若问题有解,则输出全部摆法(每两种摆法之间空一行)。
若问题无解,则输出 None。

要求:试探的顺序按从上到下逐行进行,其中每一行按从左到右的逐格进行,请参看输出样例2。

输入样例1

3

输出样例1

None

输入样例2

6

输出样例2

. Q . . . .
. . . Q . .
. . . . . Q
Q . . . . .
. . Q . . .
. . . . Q .

. . Q . . .
. . . . . Q
. Q . . . .
. . . . Q .
Q . . . . .
. . . Q . .

. . . Q . .
Q . . . . .
. . . . Q .
. Q . . . .
. . . . . Q
. . Q . . .

. . . . Q .
. . Q . . .
Q . . . . .
. . . . . Q
. . . Q . .
. Q . . . .

代码:

#include <iostream>
using namespace std;
int N, flag = 0;
int f(int x,int y,char a[][1000]){
	int x1,i,y1=y,m;
	for (i = y-1; i >= 0; i--){
		x1 = 0, y1 = i ;
		m = y - y1;
		while (a[y1][x1] != 'Q')
			x1++;
		if (x1 == x)
			return 0;
		if (x1 - m == x || x1 + m == x)
			return 0;
	}
	return 1;
}
int s(int x, char a[][1000])
{
	int i, j;
	if (x == N)
	{
        if(flag)
            cout << endl;
		flag = 1;
		for (i = 0; i<x; i++){
			for (j = 0; j < N; j++){
				if (a[i][j] == 'Q')
					cout << a[i][j];
				else
					cout << ".";
                if(j!=N-1)
                    cout<<' ';
			}
			cout << endl;
		}
		return 0;
	}
	for (j = 0; j < N; j++)
		if (f(j,x , a)){
		a[x][j] = 'Q';
		s(x+1, a);
		a[x][j] = '.';
		}
	return 1;
}
int main()
{
	char a[1000][1000];
	cin >> N;
	s(0, a);
	if (flag == 0)
		cout << "None"<<endl ;
	return 0;
}

在这里插入图片描述
在这里插入图片描述

0-1背包

给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。

输入格式:
共有n+1行输入: 第一行为n值和c值,表示n件物品和背包容量c; 接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。

输出格式:
输出装入背包中物品的最大总价值。

输入样例:
在这里给出一组输入。例如:

5 10
2 6
2 3
6 5
5 4
4 6

输出样例:
在这里给出相应的输出。例如:

15

代码:

#include <iostream>
using namespace std;
int dp[105][1005] = { 0 };
int n, c;
int w[105], v[105];
void solve(){
	for (int i = 0; i<n; i++){
		for (int j = 0; j <= c; j++){
			if (j<w[i]){
				dp[i + 1][j] = dp[i][j];
			}
			else{
				if (dp[i][j - w[i]] + v[i]>dp[i][j])
					dp[i + 1][j] = dp[i][j - w[i]] + v[i];
				else
					dp[i + 1][j] = dp[i][j];
			}
		}
	}
}

int main(){
	cin >> n >> c;
	for (int i = 0; i<n; i++){
		cin >> w[i] >> v[i];
	}
	solve();
	cout << dp[n][c] << endl;
	return 0;
}

在这里插入图片描述

整数拆分

将一个正整数拆分成若干个正整数的和。

输入格式:
一个正整数n

输出格式:
若干行,每行一个等式(每个数或者等号间都有一个空格,第一个数前没有空格,最后一个数后面没有空格,数与数之间要求非降序排列)。最后一行给出解的总个数

输入样例:
在这里给出一组输入。例如:

4

输出样例:
在这里给出相应的输出。例如:

4 = 1 + 1 + 1 + 1
4 = 1 + 1 + 2
4 = 1 + 3
4 = 2 + 2
4

代码:

#include <iostream>
#include <vector>
using namespace std;
int n, num;
vector<int> v;

void dfs(int k, int sum) {
	if (sum > n) return;
	if (sum == n) {
		cout << n << " = ";
		for (int i = 0; i < v.size(); i++) {
			if (i) cout << " + ";
			cout << v[i];
		}
		cout << endl;
		num++;
		return;
	}
	for (int i = k; i < n; i++) {
		v.push_back(i);
		dfs(i, sum + i);
		v.pop_back();
	}
}

int main() {
	cin >> n;
	dfs(1, 0);
	cout << num<<endl;
	return 0;
}

在这里插入图片描述

666

666.png

小明有一张m*n的好习惯记录卡,记录每一天的好习惯目标达成度(数字0-9表示)。某天目标完成达成,就在当天的格子里写上数字6,目标没有完全达成就写上一个小于6的数字(0-5),目标超额完成就写上一个大于6的数字(7-9)。记录卡上如果能找到一条长度为3的路径并且路径上的三个数字都大于等于6(这里的路径是指从某个格子出发,可以向左、右、上、下格子移动,并且不能重复经过一个格子),则小明就能得到一个“666”奖励。
请你帮小明统计下他总共能得到多少“666”奖励。

输入格式:
输入第一行给出两个正整数m,n(1=<m,n<=100),随后是m行,每行包含n个0-9之间的数字。

输出格式:
先输出m行,每行包括n个整数,代表从当前格子出发得到的“666”奖励个数,中间用空格分割,最后一个数字后面不带空格。然后再在下一行输出得到的“666”奖励总数。

输入样例:

3 3
6 6 7
3 8 3
7 9 5

输出样例:

2 1 2
0 3 0
1 1 0
10

代码:

#include <iostream>
#include <vector>
using namespace std;
int n, m, b[10000][10000] ,a[10000][10000];
int s(int x, int y, int w, int fn){
	int z = 0, z1 = 0;
	if (a[x][y + 1] >= 6 && fn != 3){
		if (w == 2)
			z1++;
		else
			z += s(x, y + 1, w + 1, 1);
	}
	if (a[x + 1][y] >= 6 && fn != 4){
		if (w == 2)
			z1++;
		else
			z += s(x + 1, y, w + 1, 2);
	}
	if (a[x][y - 1] >= 6 && fn != 1){
		if (w == 2)
			z1++;
		else
			z += s(x, y - 1, w + 1, 3);
	}
	if (a[x - 1][y] >= 6 && fn != 2){
		if (w == 2)
			z1++;
		else
			z += s(x - 1, y, w + 1, 4);
	}
	if (w == 2)
		return z1;
	else
		return z;
}
int main() {
	int sum=0;
	cin >> m >> n;
	for (int i = 1; i <= m; i++)
		for (int j = 1; j <= n; j++)
			cin >> a[i][j];
	for (int i = 1; i <= m; i++)
		for (int j = 1; j <= n; j++){
		if (a[i][j] >= 6)
			b[i][j] = s(i, j, 1, 0);
		else
			b[i][j] = 0;
		}
	for (int i = 1; i <= m; i++){
		for (int j = 1; j <= n; j++){
			if (j != 1)cout << " ";
			cout << b[i][j];
			sum += b[i][j];
		}
		cout << endl;
	}
	cout << sum<<endl;
	return 0;
}

在这里插入图片描述

工作分配问题

设有n件工作分配给n个人。将工作i分配给第j个人所需的费用为cij 。 设计一个算法,对于给定的工作费用,为每一个人都分配1 件不同的工作,并使总费用达到最小。

输入格式:
输入数据的第一行有1 个正整数n (1≤n≤20)。接下来的n行,每行n个数,表示工作费用。

输出格式:
将计算出的最小总费用输出到屏幕。

输入样例:
在这里给出一组输入。例如:

3
10 2 3
2 3 4
3 4 5

输出样例:
在这里给出相应的输出。例如:

9

代码:

#include <iostream>
#include <algorithm>
using namespace std;
int n, cost = 0;
int c[100][100];
void work(int i, int countt)
{
	if (i > n && countt < cost)
	{
		cost = countt;
		return;
	}
	if (countt< cost)
	{
		for (int j = 1; j <= n; j++)
		{
			if (c[0][j] == 0)
			{
				c[0][j] = 1;
				work(i + 1, countt + c[i][j]);
				c[0][j] = 0;
			}
		}
	}
}
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> c[i][j];
			c[0][j] = 0; 
		}
		cost += c[i][i];
	}
	work(1, 0);
	cout << cost << endl;
	return 0;
}

在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页