bluecode-最小团建熟悉程度和

50 阅读4分钟

问题描述

小U加入了一个团队,团队决定举办分布式团建活动来加强新老成员间的交流。为了最大化新旧成员间的互动,需要将团队成员分成若干个由三人组成的小组,使得每个小组内成员间的熟悉程度之和最小。每个小组的熟悉程度定义为小组内成员两两之间的熟悉程度之和。小U负责计算出最优的分组方式。

矩阵familiar_matrix[i][j]表示第i个人和第j个人之间的熟悉程度。保证两人彼此的熟悉程度是一样的。

保证人数一定是3的倍数。


测试样例

样例1:

输入:N = 3,familiar_matrix = [[100, 78, 97], [78, 100, 55], [97, 55, 100]]
输出:230

样例2:

输入:N = 6,familiar_matrix = [[100, 56, 19, 87, 38, 61], [56, 100, 70, 94, 88, 94], [19, 70, 100, 94, 43, 95], [87, 94, 94, 100, 85, 11], [38, 88, 43, 85, 100, 94], [61, 94, 95, 11, 94, 100]]
输出:299

样例3:

输入:N = 9,familiar_matrix = [[100, 24, 35, 45, 56, 67, 78, 89, 90], [24, 100, 45, 56, 67, 78, 89, 90, 11], [35, 45, 100, 67, 78, 89, 90, 11, 12], [45, 56, 67, 100, 89, 90, 11, 12, 13], [56, 67, 78, 89, 100, 11, 12, 13, 14], [67, 78, 89, 90, 11, 100, 13, 14, 15], [78, 89, 90, 11, 12, 13, 100, 15, 16], [89, 90, 11, 12, 13, 14, 15, 100, 17], [90, 11, 12, 13, 14, 15, 16, 17, 100]]
输出:182

回溯

#include <climits>
#include <iostream>
#include <vector>

using namespace std;


void dfs(int N, vector<vector<int>> &familiar_matrix, vector<bool> &used,
         int current_sum, int groups_formed, int &min_sum) {
  if (groups_formed == N / 3) {
    if (current_sum < min_sum) {
      min_sum = current_sum;
    }
    return;
  }

  // Find the first unused member
  int first = -1;
  for (int i = 0; i < N; ++i) {
    if (!used[i]) {
      first = i;
      break;
    }
  }

  used[first] = true;

  // Try all possible pairs with 'first'
  for (int second = first + 1; second < N; ++second) {
    if (!used[second]) {
      used[second] = true;
      for (int third = second + 1; third < N; ++third) {
        if (!used[third]) {
          used[third] = true;
          // Calculate the familiarity of this group
          int group_sum = familiar_matrix[first][second] +
                          familiar_matrix[first][third] +
                          familiar_matrix[second][third];
          dfs(N, familiar_matrix, used, current_sum + group_sum,
                    groups_formed + 1, min_sum);
          used[third] = false;
        }
      }
      used[second] = false;
    }
  }

  used[first] = false;
}

int solution(int N, std::vector<std::vector<int>> familiar_matrix) {
  int min_sum = INT_MAX;
  vector<bool> used(N, false);
  dfs(N, familiar_matrix, used, 0, 0, min_sum);
  return min_sum;
}

int main() {
  //  You can add more test cases here
  std::vector<std::vector<int>> familiar_matrix1 = {
      {100, 78, 97}, {78, 100, 55}, {97, 55, 100}};
  std::vector<std::vector<int>> familiar_matrix2 = {
      {100, 56, 19, 87, 38, 61}, {56, 100, 70, 94, 88, 94},
      {19, 70, 100, 94, 43, 95}, {87, 94, 94, 100, 85, 11},
      {38, 88, 43, 85, 100, 94}, {61, 94, 95, 11, 94, 100}};

  std::cout << (solution(3, familiar_matrix1) == 230) << std::endl;
  std::cout << (solution(6, familiar_matrix2) == 299) << std::endl;

  return 0;
}

dp

#include <vector>
#include <climits>
#include <algorithm>
#include <iostream>

using namespace std;

int solution(int N, vector<vector<int>>& familiar_matrix) {
    const int INF = 1e9;
    vector<int> dp(1 << N, INF);
    dp[0] = 0; // 初始状态:无人被选

    for (int mask = 0; mask < (1 << N); mask++) {
        if (dp[mask] == INF) continue; // 跳过无效状态

        // 找到第一个未被选的人
        int first = -1;
        for (int i = 0; i < N; i++) {
            if (!(mask & (1 << i))) {
                first = i;
                break;
            }
        }
        if (first == -1) continue; // 所有人已被选

        // 尝试所有可能的 3 人组合(包含 first)
        for (int second = first + 1; second < N; second++) {
            if (mask & (1 << second)) continue; // 已选
            for (int third = second + 1; third < N; third++) {
                if (mask & (1 << third)) continue; // 已选

                int new_mask = mask | (1 << first) | (1 << second) | (1 << third);
                int group_sum = familiar_matrix[first][second] + 
                                familiar_matrix[first][third] + 
                                familiar_matrix[second][third];
                dp[new_mask] = min(dp[new_mask], dp[mask] + group_sum);
            }
        }
    }

    return dp[(1 << N) - 1]; // 所有人被选时的最小和
}

int main() {
  //  You can add more test cases here
  std::vector<std::vector<int>> familiar_matrix1 = {
      {100, 78, 97}, {78, 100, 55}, {97, 55, 100}};
  std::vector<std::vector<int>> familiar_matrix2 = {
      {100, 56, 19, 87, 38, 61}, {56, 100, 70, 94, 88, 94},
      {19, 70, 100, 94, 43, 95}, {87, 94, 94, 100, 85, 11},
      {38, 88, 43, 85, 100, 94}, {61, 94, 95, 11, 94, 100}};

  std::cout << (solution(3, familiar_matrix1) == 230) << std::endl;
  std::cout << (solution(6, familiar_matrix2) == 299) << std::endl;

  return 0;
}