【算法设计与分析】 【 回溯法】 【C语言】 运动员最佳匹配问题
- 问题描述
- 解决思路
- 代码展现
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] 。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
编程任务:
设计一个算法,对于给定的男女运动员竞赛优势,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大
数据输入:
由文件input.txt 给出输入数据。第一行有1 个正整数n (1≤n≤20)。接下来的2n 行,每行n 个数。前n 行是p,后n 行是q。
结果输出:
将计算出的男女双方竞赛优势的总和的最大值输出。
输入文件示例
3
10 2 3
2 3 4
3 4 5
2 2 2
3 5 3
4 5 1
输出文件示例
52
解决思路
1、这道题类似于 8-皇后问题, 区别在于这道题需要将所有的解找出后, 再找最优解。
2、另外需要注意的几处地方在代码中标注了。
代码
#include <stdio.h>
#include <stdlib.h>
int if_OK(int c[], int K){ // 判断是否为一个解
int i , flag;
int arr[21] = {0};
for(i = 1; i <= K; i++){
arr[c[i]] += 1;
}
for(i = 1, flag = 1; i <= K; i++){
if(arr[i] != 1){
flag = 0;
break;
}
}
return flag;
}
int is_part(int c[], int K){ // 判断是否为部分解
int i , flag;
int arr[21] = {0};
for(i = 1; i <= K; i++){
arr[c[i]] += 1;
}
for(i = 1, flag = 0; i <= K; i++){ // 这里与 if_OK 有区别
if(arr[i] > 1){
flag = 0;
break;
}
else if(arr[i] == 0){
flag = 1;
}
}
return flag;
}
int func(int c[], int f[21][21], int K){ // 计算该解情况下,男女运动员竞赛优势的总和
int i, count = 0;
for(i = 1; i <= K; i++){
count += f[i][c[i]];
}
return count;
}
int main()
{
int i, j;
int N;
scanf("%d", &N);
int p[21][21], q[21][21], f[21][21]; // p 记录男运动员的竞赛优势、 q记录女运动员的、 f是男女运动员匹配后的 。 并且 数组都是从 1 开始的。
for(i = 1; i <= N; i++){
for(j = 1; j <= N; j++){
scanf("%d", &(p[i][j]));
}
}
for(i = 1; i <= N; i++){
for(j = 1; j <= N; j++){
scanf("%d", &(q[i][j]));
f[j][i] = q[i][j] * p[j][i]; // 注意此处f、 p、 q的数组下标 !!!
}
}
int com[21] = {0}; // 用来记录男女队员的匹配, com【i】中的 i 代表男队员、com【i】代表女队员
int k = 1, tmp = 0, count = 0; // tmp 是当前解的优势值, count 是最优的优势值
while(k >= 1 && k <= N){ // 注意 k <= N !!!
while(com[k] <= N){
com[k] = com[k] + 1;
if(if_OK(com, N)){ // 表示该com【】为一组解
tmp = func(com, f, N);
if(tmp > count) count = tmp; // 记录最优解
break;
}
else if(is_part(com, N)) k = k+1; // 部分解
}
com[k] = 0;
k = k-1;
}
printf("%d" , count);
return 0;
}