实验内容: 一、算法实现题: 1、问题描述: 羽毛球队有男女运动员各n人,给定2个n×n矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]则是女运动员i和男运动员j配合的女运动员竞赛优势。 由于技术配合和心理状态等各种因素的影响,P[i][j]不一定等于Q[j][i]。男运动员i和女运动员j配对组成混合双打的男女双方竞赛优势为P[i][j]*Q[j][i]。设计一个算法,计算男女运动员的最佳配对法,使各组男女双方竞赛优势的总和达到最大。
2、编程任务: 设计一个算法,对于给定的男女运动员竞赛优势,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
3、数据输入: 由文件input.txt给出输入数据;第一行有1个正整数n(1≤n≤20);接下来的2n行,每行n个数,前n行是P,后n行是Q。
4、结果输出: 将计算的男女双方竞赛优势的总和的最大值输出到文件output.txt。 输入文件示例 输出文件示例 intput.txt output.txt 3 52 10 2 3 2 3 4 3 4 5 2 2 2 3 5 3 4 5 1 二、解题思路 1、求问题的解空间 对于n个男运动员,从第1个开始搭配女运动员:第1个有n种搭配方法,第2个有n-1种搭配方法……第n个有n-(n-1)种搭配方法;根据问题给出的示例:输入n的值为3,表示男女运动员各有3名; 男运动员 1 2 3按顺序搭配女运动员,他们分别对应的女运动员可以是: 女运动员 1 2 3、1 3 2、2 1 3、2 3 1、3 1 2、3 2 1 所以其解空间是{(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)},整个问题可看成是1,2,3的全排列问题,将解空间组织成一棵排列树如下
|
A
B
C
D
E
F
G
H
J
I
K
L
M
N
P
O
1
1
1
1
1
2
3
3
2
3
2
3
3
2
2
运动员最佳配对问题解空间树
男运动员3号------>
男运动员2号------>
男运动员1号------>
解空间树的第i层到第i+1层边上的标号给出了变量的值。从树根到叶的任一路径表示解空间中的一个元素。
2、用深度优先的搜索策略搜索整个解空间
用一个数组x记录可行解,并且赋初值为{0,1,2…n},x[i]表示第i个男生配对的女生号;所以第i个男生与第x[i]个女生双方竞赛优势为P[i-1][x[i]-1]*Q[x[i]-1][i-1];
用t表示递归深度,初值为1,表示第1个男生开始搭配;t可以由n来控制。
当t>n时,表示算法已搜索到叶子结点,此时根据x的记录计算男女双方竞赛优势的总和s,算法如下:
P[j][x[j+1]-1]*Q[x[j+1]-1][j]表示第j+1个男运动员与第x[j+1]个女运动员配对组成混合双打的男女双方竞赛优势
int s=0; //记录当前男女双方竞赛优势总和,计算前值为0
for(int j=0;j<n;j++)
s=s+P[j][x[j+1]-1]*Q[x[j+1]-1][j];
并判断s是否大于当前记录的男女双方竞赛优势的总和的最大值sum,若s>sum,则给sum赋值s;
当t<=n时,表示还没有搜索到叶子结点,则需要继续往下搜索,从i=t开始搜索至i=n;
for(int i=t;i<=n;i++){
Swap(&x[t],&x[i]); //交换x[t]和x[i]的值,第t和第i个男运动员交换搭档
//没有约束函数和限界函数
Backtrack(t+1); //进行第t+1个男运动员配对
Swap(&x[t],&x[i]); //交换回来它们的值,以便于与另外的另外的男运动员交换
}
三、算法描述
#include "fstream.h"
ifstream fin("input.txt");
ofstream fout("output.txt");
int **P=NULL;
int **Q=NULL;
int *x=NULL;
int sum=0; //记录男女双方竞赛优势的总和的最大值
int n;
//交换两个数
void Swap(int *b,int *y)
{
int z;
z=*b;
*b=*y;
*y=z;
}
//求男女双方竞赛优势总和最大值函数
void Sum()
{
int s=0; //记录当前男女双方竞赛优势总和
for(int j=0;j<n;j++)
s+=P[j][x[j+1]-1]*Q[x[j+1]-1][j];
if(s>=sum) sum=s; //输出值
}
//回溯法搜索排列树
void Backtrack(int t)
{
if(t>n) Sum(); //当到叶子节点时
else
for(int i=t;i<=n;i++)
{
//没有约束函数和限界函数的全排列问题
Swap(&x[t],&x[i]);
Backtrack(t+1); //进行第t+1个男运动员配对
Swap(&x[t],&x[i]);
}
}
void main()
{
int i,j;
int t=1;
fin>>n;
if(n<1||n>20)
{
fout<<"请输入正确的n的值!";
return;
}
//动态分配数组空间
x=new int[n+1];
for(i=0;i<n+1;i++)
x[i]=i;
//P,Q分配n行n列:从第0行0列到第n-1行第n-1列
P=new int*[n];
for(i=0;i<n;i++)
P[i]=new int[n];
Q=new int*[n];
for(i=0;i<n;i++)
Q[i]=new int[n];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
fin>>P[i][j];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
fin>>Q[i][j];
Backtrack(t);
fout<<sum; //输出男女双方竞赛优势的总和的最大值
//释放空间
for(int k=0;k<n;k++)
{
delete[] P[k];
P[k]=NULL;
}
for(k=0;k<n;k++)
{
delete[] Q[k];
Q[k]=NULL;
}
fin.close();
fout.close();
return;
}
数据记录和计算:
序号 |
输入文件(input.txt) |
输出文件(output.txt) |
1. |
3 10 2 3 2 3 4 3 4 5 2 2 2 3 5 3 4 5 1 |
52 |
2. |
5 50 43 1 58 60 87 22 5 62 71 62 98 97 27 38 56 57 96 73 71 92 36 43 27 95 2 95 80 28 33 4 51 97 61 1 26 15 90 94 32 29 19 71 35 84 22 85 39 30 80 |
36077 |
3. |
8 63 69 21 15 42 59 42 86 1 75 77 31 52 24 98 73 40 49 58 4 7 82 39 82 40 30 64 63 27 5 8 58 98 46 16 49 31 48 79 92 53 17 4 82 77 95 71 68 45 44 31 73 38 62 62 98 25 7 39 95 3 75 47 75 74 74 80 93 55 75 21 78 7 87 61 50 29 13 4 59 9 22 64 48 34 66 56 26 60 51 79 2 91 40 89 45 80 65 51 65 84 9 90 32 82 58 13 68 62 30 80 54 20 6 53 16 38 79 9 45 36 1 75 17 6 41 1 14 |
40653 |
4. |
10 84 39 87 86 86 61 8 48 35 65 8 87 57 8 94 98 88 51 89 49 52 57 36 19 22 77 56 94 7 37 88 98 53 39 33 90 5 96 68 67 21 14 40 32 71 86 77 25 17 31 87 13 22 94 9 52 85 25 19 22 10 54 43 34 37 39 47 14 69 23 2 98 77 98 6 82 23 29 51 74 16 12 95 60 4 51 51 7 57 9 66 7 84 57 93 71 6 36 53 62 65 92 53 32 2 47 60 15 36 1 48 30 72 34 38 51 40 14 57 73 19 50 75 96 51 98 7 37 77 34 85 46 3 90 89 99 41 75 14 42 29 81 99 21 87 86 87 1 86 65 14 76 71 63 56 15 69 74 45 27 37 96 89 88 32 23 61 77 39 63 99 85 80 89 80 44 68 6 91 4 47 18 15 86 64 79 46 73 64 22 70 2 57 92 86 30 82 50 35 63 |
62502 |
5. |
10 2 36 94 52 17 19 93 40 43 90 63 45 21 58 91 85 83 79 54 69 71 36 28 55 43 1 65 48 22 59 90 42 43 63 47 58 39 92 88 87 62 67 31 35 78 49 3 53 44 1 85 22 32 29 2 28 30 65 72 17 77 12 29 55 6 96 51 68 67 15 21 9 89 21 65 90 74 14 39 99 90 91 58 21 25 79 25 40 17 39 70 38 64 34 84 80 55 90 23 8 8 86 64 30 100 75 77 18 95 28 54 65 52 53 5 50 17 23 89 88 17 25 16 99 60 16 43 76 79 20 75 82 95 56 35 30 75 3 72 99 56 87 100 46 75 27 54 44 94 8 60 50 83 45 44 51 85 78 65 34 86 15 3 52 56 94 85 25 98 90 81 1 68 50 1 39 26 46 56 57 87 61 34 21 22 71 86 8 4 11 94 16 58 8 96 25 96 42 83 92 |
65487 |
6. |
12 27 73 61 86 92 53 36 82 71 14 85 68 25 35 91 10 59 74 21 96 18 15 32 93 58 27 31 15 9 95 4 6 89 70 34 60 58 65 9 43 15 62 67 21 56 4 32 97 3 93 87 13 49 89 89 45 87 86 43 51 34 81 42 61 9 69 37 99 63 52 100 35 57 13 4 45 43 80 39 27 40 38 69 89 92 64 10 42 85 47 80 74 22 97 74 82 5 53 81 71 99 24 89 85 16 9 66 39 14 40 68 13 99 6 44 30 46 96 63 55 80 99 58 52 47 65 12 43 85 9 4 84 92 39 54 22 81 41 52 90 22 22 73 73 58 87 21 19 5 92 69 67 96 42 52 66 48 95 85 86 89 20 89 55 100 85 22 96 36 100 90 31 35 65 86 10 60 69 38 62 88 20 79 71 63 24 13 99 100 45 2 27 88 7 85 58 69 94 94 92 10 29 5 59 56 43 97 43 53 19 6 88 94 98 28 51 69 33 79 9 85 25 100 33 34 57 69 93 84 15 1 8 15 87 56 80 99 74 66 1 42 88 92 89 3 74 32 3 5 28 68 84 31 95 77 44 59 52 40 16 56 8 88 84 6 98 85 25 53 78 23 66 44 65 80 5 42 82 43 77 93 98 100 35 21 78 37 10
|
84593 |
结论(结果):
这次实验是用回溯法来解决运动员最佳配对问题,程序成功通过编译,在起初调试的时候总是出现应用程序错误,“"0x00401057"指令引用的"0x00000000"内存不能为"written"。要终止程序,请单击"确定"。”后来经过单目调试,一步步解决了内存问题,至能正常运行,并得到正确的输出结果。
小结:
通过这次实验,基本上掌握了用回溯法解题的算法框架,首先要理解问题,找出问题的解空间;其次是根据解空间画出解空间树;最后按照深度优先的搜索策略来搜索整棵树来得到最优解。
实验让我更进一步地理解了回溯法的深度优先搜索策略,从根结点出发,根结点成为活结点,成为当前的扩展结点,搜索向纵深方向移至一个新结点,这个新结点会成为新的活结点,在当前扩展结点处不能再向纵深方向移动,当前扩展结点就成为死结点;此时往回移动至最近的一个活结点,就这样递归地在解空间中搜索,直到找到所要求的解或解空间中已无活结点为止。
自己以前的作业,做一下收藏而已
来源:CSDN
作者:p2liu
链接:https://blog.csdn.net/pengluer/article/details/4374222