给你两组点,其中第一组中有 size1 个点,第二组中有 size2 个点,且 size1 >= size2 。
任意两点间的连接成本 cost 由大小为 size1 x size2 矩阵给出,其中 cost[i][j] 是第一组中的点 ij 的连接成本。 如果两个组中的每个点都与另一组中的一个或多个点连接,则称这两组点是连通的。 
返回连通两组点所需的最小成本。
示例 1: 
与第二组的点集 s 的最小连通成本(因为 size}_1 \ge \textit{size}_2,所以将第二组作为点集),有四种情况:
i = 0 且 s = 0:
  两组点都为空,因此最小连通成本为 dp}[0][0] = 0。
i = 0 且 s \ne 0:
  第一组的点为空,第二组的点不为空,因此无法连通,令 dp}[0][s] = \infty。
i \ne 0 且 s = 0:
  第一组的点不为空,第二组的点为空,因此无法连通,令 dp}[i][0] = \infty。
i \ne 0 且 s \ne 0:
  考虑第一组第 i - 1 个点与第二组点集 s 的第 k 个点连接,使用 s_{-k 表示点集 s 去除第 k 个点后的剩余点集,那么连通成本 c 有三种情况:
第二组点集 s 的第 k 个点不再与其他点连接,那么 c = \textit{dp}[i][s_{-k}] + \textit{cost}[i - 1][k];
第一组第 i - 1 个点不再与其他点连接,那么 c = \textit{dp}[i - 1][s] + \textit{cost}[i - 1][k];
第一组第 i - 1 个点和第二组点集 s 的第 k 个点都不再与其他点连接,那么 c = \textit{dp}[i - 1][s_{-k}] + \textit{cost}[i - 1][k]。
 
  枚举第一组第 i - 1 个点与第二组点集 s 中任一 k \in s 的点连接,那么状态转移方程如下:
 
\textit{dp}[i][s] = \min_{k \in s} \big { {\min { { \textit{dp}[i][s_{-k}], \textit{dp}[i - 1][s], \textit{dp}[i - 1][s_{-k}] } } + \textit{cost}[i - 1][k]} \big }
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Solution  {public :    int  connectTwoGroups (vector<vector<int >>& cost)           int  size1 = cost.size (), size2 = cost[0 ].size (), m = 1  << size2;         vector<vector<int >> dp (size1 + 1 , vector <int >(m, INT_MAX / 2 ));         dp[0 ][0 ] = 0 ;         for  (int  i = 1 ; i <= size1; i++) {             for  (int  s = 0 ; s < m; s++) {                 for  (int  k = 0 ; k < size2; k++) {                     if  ((s & (1  << k)) == 0 ) {                         continue ;                     }                     dp[i][s] = min (dp[i][s], dp[i][s ^ (1  << k)] + cost[i - 1 ][k]);                     dp[i][s] = min (dp[i][s], dp[i - 1 ][s] + cost[i - 1 ][k]);                     dp[i][s] = min (dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost[i - 1 ][k]);                 }             }         }         return  dp[size1][m - 1 ];     } }; 
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class  Solution  {    public  int  connectTwoGroups (List<List<Integer>> cost)  {         int  size1  =  cost.size(), size2 = cost.get(0 ).size(), m = 1  << size2;         int [][] dp = new  int [size1 + 1 ][m];         for  (int  i  =  0 ; i <= size1; i++) {             Arrays.fill(dp[i], Integer.MAX_VALUE / 2 );         }         dp[0 ][0 ] = 0 ;         for  (int  i  =  1 ; i <= size1; i++) {             for  (int  s  =  0 ; s < m; s++) {                 for  (int  k  =  0 ; k < size2; k++) {                     if  ((s & (1  << k)) == 0 ) {                         continue ;                     }                     dp[i][s] = Math.min(dp[i][s], dp[i][s ^ (1  << k)] + cost.get(i - 1 ).get(k));                     dp[i][s] = Math.min(dp[i][s], dp[i - 1 ][s] + cost.get(i - 1 ).get(k));                     dp[i][s] = Math.min(dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost.get(i - 1 ).get(k));                 }             }         }         return  dp[size1][m - 1 ];     } } 
[sol1-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  class  Solution  {    public  int  ConnectTwoGroups (IList<IList<int >> cost )         int  size1 = cost.Count, size2 = cost[0 ].Count, m = 1  << size2;         int [][] dp = new  int [size1 + 1 ][];         for  (int  i = 0 ; i <= size1; i++) {             dp[i] = new  int [m];             Array.Fill(dp[i], int .MaxValue / 2 );         }         dp[0 ][0 ] = 0 ;         for  (int  i = 1 ; i <= size1; i++) {             for  (int  s = 0 ; s < m; s++) {                 for  (int  k = 0 ; k < size2; k++) {                     if  ((s & (1  << k)) == 0 ) {                         continue ;                     }                     dp[i][s] = Math.Min(dp[i][s], dp[i][s ^ (1  << k)] + cost[i - 1 ][k]);                     dp[i][s] = Math.Min(dp[i][s], dp[i - 1 ][s] + cost[i - 1 ][k]);                     dp[i][s] = Math.Min(dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost[i - 1 ][k]);                 }             }         }         return  dp[size1][m - 1 ];     } } 
[sol1-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func  min (a, b int ) int  {    if  a > b {         return  b     }     return  a } func  connectTwoGroups (cost [][]int ) int  {    size1, size2, m := len (cost), len (cost[0 ]), 1  << len (cost[0 ])     dp := make ([][]int , size1 + 1 )     for  i := 0 ; i <= size1; i++ {         dp[i] = make ([]int , m)     }     for  s := 1 ; s < m; s++ {         dp[0 ][s] = 0x3f3f3f3f      }     for  i := 1 ; i <= size1; i++ {         for  s := 0 ; s < m; s++ {             dp[i][s] = 0x3f3f3f3f              for  k := 0 ; k < size2; k++ {                 if  (s & (1  << k)) == 0  {                     continue                  }                 dp[i][s] = min(dp[i][s], dp[i][s ^ (1  << k)] + cost[i - 1 ][k])                 dp[i][s] = min(dp[i][s], dp[i - 1 ][s] + cost[i - 1 ][k])                 dp[i][s] = min(dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost[i - 1 ][k])             }         }     }     return  dp[size1][m - 1 ] } 
[sol1-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int  connectTwoGroups (int ** cost, int  costSize, int * costColSize)  {    int  size1 = costSize, size2 = costColSize[0 ], m = 1  << size2;      int  dp[size1 + 1 ][m];     memset (dp, 0x3f , sizeof (dp));     dp[0 ][0 ] = 0 ;     for  (int  i = 1 ; i <= size1; i++) {         for  (int  s = 0 ; s < m; s++) {             for  (int  k = 0 ; k < size2; k++) {                 if  ((s & (1  << k)) == 0 ) {                     continue ;                 }                 dp[i][s] = fmin(dp[i][s], dp[i][s ^ (1  << k)] + cost[i - 1 ][k]);                 dp[i][s] = fmin(dp[i][s], dp[i - 1 ][s] + cost[i - 1 ][k]);                 dp[i][s] = fmin(dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost[i - 1 ][k]);             }         }     }     return  dp[size1][m - 1 ]; } 
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  Solution :    def  connectTwoGroups (self, cost: List [List [int ]] ) -> int :         size1, size2 = len (cost), len (cost[0 ])         m = 1  << size2         dp = [[float ("inf" )] * m for  _ in  range (size1 + 1 )]         dp[0 ][0 ] = 0          for  i in  range (1 , size1 + 1 ):             for  s in  range (m):                 for  k in  range (size2):                     if  (s & (1  << k)) == 0 :                         continue                      dp[i][s] = min (dp[i][s], dp[i][s ^ (1  << k)] + cost[i - 1 ][k])                     dp[i][s] = min (dp[i][s], dp[i - 1 ][s] + cost[i - 1 ][k])                     dp[i][s] = min (dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost[i - 1 ][k])                  return  dp[size1][m - 1 ] 
[sol1-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var  connectTwoGroups = function (cost ) {    const  size1 = cost.length ;     const  size2 = cost[0 ].length ;     const  m = 1  << size2;     const  dp = Array .from (Array (size1 + 1 ), () =>  new  Array (m).fill (Number .MAX_SAFE_INTEGER  / 2 ));     dp[0 ][0 ] = 0 ;     for  (let  i = 1 ; i <= size1; i++) {         for  (let  s = 0 ; s < m; s++) {         for  (let  k = 0 ; k < size2; k++) {             if  ((s & (1  << k)) === 0 ) {             continue ;             }             dp[i][s] = Math .min (dp[i][s], dp[i][s ^ (1  << k)] + cost[i - 1 ][k]);             dp[i][s] = Math .min (dp[i][s], dp[i - 1 ][s] + cost[i - 1 ][k]);             dp[i][s] = Math .min (dp[i][s], dp[i - 1 ][s ^ (1  << k)] + cost[i - 1 ][k]);         }         }     }     return  dp[size1][m - 1 ]; }; 
转移方程的 dp[i][] 计算只与 dp[i - 1][ ] 和 dp[i][*] 相关,因此我们可以只使用一维数组来保存,从而节省空间。
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class  Solution  {public :    int  connectTwoGroups (vector<vector<int >>& cost)           int  size1 = cost.size (), size2 = cost[0 ].size (), m = 1  << size2;         vector<int > dp1 (m, INT_MAX / 2 ) , dp2 (m)  ;         dp1[0 ] = 0 ;         for  (int  i = 1 ; i <= size1; i++) {             for  (int  s = 0 ; s < m; s++) {                 dp2[s] = INT_MAX / 2 ;                 for  (int  k = 0 ; k < size2; k++) {                     if  ((s & (1  << k)) == 0 ) {                         continue ;                     }                     dp2[s] = min (dp2[s], dp2[s ^ (1  << k)] + cost[i - 1 ][k]);                     dp2[s] = min (dp2[s], dp1[s] + cost[i - 1 ][k]);                     dp2[s] = min (dp2[s], dp1[s ^ (1  << k)] + cost[i - 1 ][k]);                 }             }             dp1.swap (dp2);         }         return  dp1[m - 1 ];     } }; 
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class  Solution  {    public  int  connectTwoGroups (List<List<Integer>> cost)  {         int  size1  =  cost.size(), size2 = cost.get(0 ).size(), m = 1  << size2;         int [] dp1 = new  int [m];         Arrays.fill(dp1, Integer.MAX_VALUE / 2 );         int [] dp2 = new  int [m];         dp1[0 ] = 0 ;         for  (int  i  =  1 ; i <= size1; i++) {             for  (int  s  =  0 ; s < m; s++) {                 dp2[s] = Integer.MAX_VALUE / 2 ;                 for  (int  k  =  0 ; k < size2; k++) {                     if  ((s & (1  << k)) == 0 ) {                         continue ;                     }                     dp2[s] = Math.min(dp2[s], dp2[s ^ (1  << k)] + cost.get(i - 1 ).get(k));                     dp2[s] = Math.min(dp2[s], dp1[s] + cost.get(i - 1 ).get(k));                     dp2[s] = Math.min(dp2[s], dp1[s ^ (1  << k)] + cost.get(i - 1 ).get(k));                 }             }             System.arraycopy(dp2, 0 , dp1, 0 , m);         }         return  dp1[m - 1 ];     } } 
[sol2-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  class  Solution  {    public  int  ConnectTwoGroups (IList<IList<int >> cost )         int  size1 = cost.Count, size2 = cost[0 ].Count, m = 1  << size2;         int [] dp1 = new  int [m];         Array.Fill(dp1, int .MaxValue / 2 );         int [] dp2 = new  int [m];         dp1[0 ] = 0 ;         for  (int  i = 1 ; i <= size1; i++) {             for  (int  s = 0 ; s < m; s++) {                 dp2[s] = int .MaxValue / 2 ;                 for  (int  k = 0 ; k < size2; k++) {                     if  ((s & (1  << k)) == 0 ) {                         continue ;                     }                     dp2[s] = Math.Min(dp2[s], dp2[s ^ (1  << k)] + cost[i - 1 ][k]);                     dp2[s] = Math.Min(dp2[s], dp1[s] + cost[i - 1 ][k]);                     dp2[s] = Math.Min(dp2[s], dp1[s ^ (1  << k)] + cost[i - 1 ][k]);                 }             }             Array.Copy(dp2, 0 , dp1, 0 , m);         }         return  dp1[m - 1 ];     } } 
[sol2-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 func  min (a, b int ) int  {    if  a > b {         return  b     }     return  a } func  connectTwoGroups (cost [][]int ) int  {    size1, size2, m := len (cost), len (cost[0 ]), 1  << len (cost[0 ])     dp1, dp2 := make ([]int , m), make ([]int , m)     for  s := 1 ; s < m; s++ {         dp1[s] = 0x3f3f3f3f      }     for  i := 1 ; i <= size1; i++ {         for  s := 0 ; s < m; s++ {             dp2[s] = 0x3f3f3f3f              for  k := 0 ; k < size2; k++ {                 if  (s & (1  << k)) == 0  {                     continue                  }                 dp2[s] = min(dp2[s], dp2[s ^ (1  << k)] + cost[i - 1 ][k])                 dp2[s] = min(dp2[s], dp1[s] + cost[i - 1 ][k])                 dp2[s] = min(dp2[s], dp1[s ^ (1  << k)] + cost[i - 1 ][k])             }         }         dp1, dp2 = dp2, dp1     }     return  dp1[m - 1 ] } 
[sol2-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int  connectTwoGroups (int ** cost, int  costSize, int * costColSize)  {    int  size1 = costSize, size2 = costColSize[0 ], m = 1  << size2;     int  dp1[m], dp2[m];     memset (dp1, 0x3f , sizeof (dp1));     dp1[0 ] = 0 ;     for  (int  i = 1 ; i <= size1; i++) {         for  (int  s = 0 ; s < m; s++) {             dp2[s] = INT_MAX / 2 ;             for  (int  k = 0 ; k < size2; k++) {                 if  ((s & (1  << k)) == 0 ) {                     continue ;                 }                 dp2[s] = fmin(dp2[s], dp2[s ^ (1  << k)] + cost[i - 1 ][k]);                 dp2[s] = fmin(dp2[s], dp1[s] + cost[i - 1 ][k]);                 dp2[s] = fmin(dp2[s], dp1[s ^ (1  << k)] + cost[i - 1 ][k]);             }         }         memcpy (dp1, dp2, sizeof (dp2));     }     return  dp1[m - 1 ]; } 
[sol2-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution :    def  connectTwoGroups (self, cost: List [List [int ]] ) -> int :         size1, size2 = len (cost), len (cost[0 ])         m = 1  << size2         dp1, dp2 = [float ("inf" )] * m, [0 ] * m         dp1[0 ] = 0          for  i in  range (1 , size1 + 1 ):             for  s in  range (m):                 dp2[s] = float ("inf" )                 for  k in  range (size2):                     if  (s & (1  << k)) == 0 :                         continue                      dp2[s] = min (dp2[s], dp2[s ^ (1  << k)] + cost[i - 1 ][k])                     dp2[s] = min (dp2[s], dp1[s] + cost[i - 1 ][k])                     dp2[s] = min (dp2[s], dp1[s ^ (1  << k)] + cost[i - 1 ][k])             dp1 = dp2[:]                  return  dp1[m - 1 ] 
[sol2-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var  connectTwoGroups = function (cost ) {    const  size1 = cost.length ;     const  size2 = cost[0 ].length ;     const  m = 1  << size2;     const  dp1 = new  Array (m).fill (Number .MAX_SAFE_INTEGER  / 2 );     const  dp2 = new  Array (m);          dp1[0 ] = 0 ;     for  (let  i = 1 ; i <= size1; i++) {         for  (let  s = 0 ; s < m; s++) {         dp2[s] = Number .MAX_SAFE_INTEGER  / 2 ;         for  (let  k = 0 ; k < size2; k++) {             if  ((s & (1  << k)) === 0 ) {             continue ;             }             dp2[s] = Math .min (dp2[s], dp2[s ^ (1  << k)] + cost[i - 1 ][k]);             dp2[s] = Math .min (dp2[s], dp1[s] + cost[i - 1 ][k]);             dp2[s] = Math .min (dp2[s], dp1[s ^ (1  << k)] + cost[i - 1 ][k]);         }         }         dp1.splice (0 , m, ...dp2);     }     return  dp1[m - 1 ]; }; 
复杂度分析