临时磨枪Day02
基本知识
- Kruskal算法按照边的权值的顺序从小到大査看一遍,如果不产生圈(重边等也算在内),就把当前这条边加人到生成树中。
- 接下来我们介绍如何判断是否产生圈。假设现在要把连接顶点u和顶点v的边e加入生成树中。如果加入之前u和v不在同一个连通分量里,那么加入e不会产生圈。反之,如果u和v在同一个连通分量里,那么一定会产生圈。可以使用并查集高效地判断是否属于同一个连通分量。
- Kruskal算法在边的排序上最费时,算法的复杂度是 O ( ∣ E ∣ log ∣ V ∣ ) O(|E|\log|V|) O(∣E∣log∣V∣)。
训练题
1584.连接所有点的最小费用
class unionFindSet {
private:
vector<int> parent;
vector<int> rank;
public:
unionFindSet(int n) {
parent.resize(n); //重新设置容量
rank.resize(n);
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 0;
}
}
int find(int x) {
if (parent[x] == x)
return x;
parent[x] = find(parent[x]);
return parent[x];
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
return;
}
if (rank[x] < rank[y]) {
parent[x] = y;
} else {
parent[y] = x;
if (rank[x] == rank[y]) {
rank[x]++;
}
}
}
bool same(int x, int y) {
return find(x) == find(y);
}
};
class Solution {
public:
int distance(vector<int> &x, vector<int> &y) {
return abs(x[0] - y[0]) + abs(x[1] - y[1]);
}
static bool compare(vector<int> &x, vector<int> &y) {
return x[2] < y[2];
}
int minCostConnectPoints(vector<vector<int>>& points) {
vector<vector<int>> edges;
edges.clear();
int n = points.size();
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
edges.push_back({i, j, distance(points[i], points[j])});
}
}
sort(edges.begin(), edges.end(), &compare);
int num = 1, res = 0;
unionFindSet ufs(n);
for (vector<int> edge : edges) {
if (!ufs.same(edge[0], edge[1])) {
num++;
res += edge[2];
ufs.unite(edge[0], edge[1]);
if (num == n) {
break;
}
}
}
return res;
}
};
修建公路
蒜头国有 n 座城市,编号分别为
0
,
1
,
2
,
3
,
…
,
n
−
1
0,1,2,3,\ldots,n-1
0,1,2,3,…,n−1。编号为 x 和 y 的两座城市之间如果要修高速公路,必须花费
x
∣
y
x∣y
x∣y 个金币,其中|
表示二进制按位或。
吝啬的国王想要花最少的价格修建高速公路,使得所有城市可以通过若干条高速公路互相达到。现在请你求出 n=2019 时,一共有多少不同的方案,能让所有城市连通并且造价最低。方案数可能很大,你只需输出对10^9+7取模的结果。
- 性质:若 x < y x < y x<y,则 x ∣ y > = y x|y >= y x∣y>=y。这表明不需要再对边的花费排序了。等于的时候造价是最低的。
- 每加入一个城市,计算造价最低的公路个数,最后相乘即可。
- 注意: 0 ∣ y = y 0|y =y 0∣y=y。从1开始,0和1建一条公路;到了2,因为 1 ∣ 2 = 3 1|2 = 3 1∣2=3,所以0和2建一条公路。
if __name__ == "__main__":
ans = 1
MOD = 10 ** 9 + 7
for i in range(1, 2019):
cur = 1
for j in range(1, i):
if i | j == i:
cur += 1
ans = ans * cur % MOD
print(ans)