a_lc_连通两组点的最小成本(状压+枚举两种连法)
任意两点间的连接成本 cost 由大小为 size1 x size2 矩阵给出,其中 cost[i][j] 是第一组中的点 i 和第二组中的点 j 的连接成本
第一组中的每个点必须至少与第二组中的一个点连接,且第二组中的每个点必须至少与第一组中的一个点连接。
1 <= size1, size2 <= 12
我当时的做法的case通过数量是45/83,可能是没有考虑完或者边界问题(没时间改),参考别人的状态压缩dp,对于第一组的每个点i:
- 第一种连法:直接连接第二组的每个点
- 第二种连法:连接第二组没有连接到的点
题目还是很良心的,不用自己通过对比size1, size2来确定哪一维用作状态压缩
const int inf=0x3f3f3f3f;
class Solution {
public:
int connectTwoGroups(vector<vector<int>>& cost) {
int n=cost.size(), m=cost[0].size(), tot=1<<m, f[n+1][tot];
memset(f, inf, sizeof f); f[0][0]=0;
for (int i=1; i<=n; i++)
for (int st=0; st<tot; st++) {
//连接第二组中任意一个点
if (f[i-1][st]!=inf) {
for (int j=0; j<m; j++) {
int nx=st|(1<<j);
f[i][nx]=min(f[i][nx], f[i-1][st]+cost[i-1][j]);
}
}
int other_st=(tot-1)^st; //第二组点中没有被连接到的所有点的状态集合
for (int subset=other_st; subset; subset=other_st&(subset-1)) { //去掉other_set的最低位的1
int sum=0;
for (int j=0; j<m; j++) if (subset&(1<<j)) {
sum+=cost[i-1][j];
}
int nx=st|subset;
f[i][nx]=min(f[i][nx], f[i-1][st]+sum); //这里一开始我写成了 f[i][subset]=...,这是错的,下一个状态没累加上初始状态
}
}
return f[n][tot-1];
}
};
复杂度分析
- Time:\(O(nm2^m)\),
- Space:\(O()\),