【算法设计与分析】 【 回溯法】 【C语言】 运动员最佳匹配问题

【算法设计与分析】 【 回溯法】 【C语言】 运动员最佳匹配问题

  1. 问题描述
  2. 解决思路
  3. 代码展现

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

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值