[LeetCode] 1595. 连通两组点的最小成本

142 阅读1分钟

👉 “Offer 驾到,掘友接招!我正在参与2022春招打卡活动点击查看 活动详情

1595. 连通两组点的最小成本

给你两组点,其中第一组中有 size1 个点,第二组中有 size2 个点,且 size1 >= size2 。

任意两点间的连接成本 cost 由大小为 size1 x size2 矩阵给出,其中 cost[i][j] 是第一组中的点 i 和第二组中的点 j 的连接成本。如果两个组中的每个点都与另一组中的一个或多个点连接,则称这两组点是连通的。换言之,第一组中的每个点必须至少与第二组中的一个点连接,且第二组中的每个点必须至少与第一组中的一个点连接。

返回连通两组点所需的最小成本。

状态定义:

f[i][j] :表示左侧已经连通了前i个点,右侧点连接状态为j的最小代价是多少

状态转移:

  • 枚举左侧第i个点,连接右侧哪些点

    • 左侧的第i个点,连接右侧的若干个未连接的点
    • 左侧的第i个点,连接右侧的一个已经连接的点

枚举子集:

/*
101  5
100  4
1    1
*/
#include<bits/stdc++.h>
using namespace std;
int main(){
   int S = 5;
   for(int sub = S; sub ; sub = (sub - 1) & S){
        cout << sub << endl;
   }
   return 0;
}

code

class Solution {
public:
    int f[13][1 << 12];
    int connectTwoGroups(vector<vector<int>>& cost) {
        memset(f, -1, sizeof f);
        int m = cost.size(), n = cost[0].size();
        f[0][0] = 0;
        int state = (1 << n) - 1;
        for(int i = 1; i <= m; i++){
            for(int j = 0; j < (1 << n); j++){
                if(f[i - 1][j] == -1) continue;
​
                //枚举子集,找未连接的点
                int rs = (~j) & state;
                for(int sub = rs; sub; sub = (sub - 1) & rs){
                    int cur = 0;
                    for(int k = 0; k < n; k++) if(sub & (1 << k)) cur += cost[i - 1][k];
                    int nxt = j | sub;
                    int val = f[i - 1][j] + cur;
                    if(f[i][nxt] == -1 or f[i][nxt] > val){
                        f[i][nxt] = val;
                    }
                }
              
                //找已经连接的点
                for(int k = 0; k < n; k++){
                    int nxt = j | (1 << k), val = f[i - 1][j] + cost[i - 1][k];
                    if(f[i][nxt] == -1 or f[i][nxt] > val) f[i][nxt] = val;     
                }
            }
        }
        return f[m][state];
    }
};