最小生成树
局域网
Kruskal的模板
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
int n, m, fa[N], sum = 0, mst = 0, cnt = 0;
int findset(int x)
{
if(x == fa[x]) return x;
else return fa[x] = findset(fa[x]);
}
struct edge
{
int u, v, w;
bool operator < (const edge &a) const {return w < a.w; }
}p[N];
vector<edge> g[N];
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i) fa[i] = i;
for (int i = 1; i <= m; ++ i)
{
scanf("%d %d %d", &p[i].u, &p[i].v, &p[i].w);
sum += p[i].w;
}
sort(p + 1, p + m + 1);
for (int i = 1; i <= m; ++ i)
{
int x = findset(p[i].u), y = findset(p[i].v);
if(x == y) continue;
cnt ++;
fa[x] = y;
mst += p[i].w;
if(cnt == n - 1) break;
}
printf("%d",sum - mst);
return 0;
}
繁忙的都市
条件一 + 条件二:这是一棵生成树哦~
条件三:这是一棵最小生成树哦
(不用写二分的,手滑了)
#include <bits/stdc++.h>
using namespace std;
const int N = 8005;
int n, m, ans = 0, cnt = 0, fa[N];
int findset(int x)
{
if(x == fa[x]) return x;
else return fa[x] = findset(fa[x]);
}
struct edge
{
int u, v, w;
bool operator < (const edge &a) const {return w < a.w; }
}e[N], p[N];
bool kruskal()
{
for (int i = 1; i <= n; ++ i) fa[i] = i;
int sum = 0;
for (int i = 1; i <= cnt; ++ i)
{
int x = findset(e[i].u), y = findset(e[i].v);
if(x == y) continue;
fa[x] = y;
sum ++;
if(sum == n - 1) return true;
}
return false;
}
int main()
{
scanf("%d %d", &n, &m);
int l = 0, r = 0, mid;
for (int i = 1; i <= m; ++ i)
{
scanf("%d %d %d", &p[i].u, &p[i].v, &p[i].w);
r = max(r, p[i].w);
}
sort(p + 1, p + m + 1);
while(l <= r)
{
mid = l + r >> 1;
cnt = 0;
for (int i = 1; i <= m; ++ i)
{
if(p[i].w > mid) break;
e[++ cnt] = p[i];
}
if(kruskal()) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d %d", n - 1, ans);
return 0;
}
连接格点
题目大大说要连通,还要花费最少,那就用最小生成树罢了。
树节点不过变成了n * m个小方格而已、
跟上面一个点连接的代价是1,跟前面一个点连接的代价是2,双向边,相邻的两个点之间才可连边。
#include <bits/stdc++.h>
using namespace std;
const int N = 2000005;
struct edge
{
int u, v, w;
bool operator < (const edge &a) const {return w < a.w; }
}e[N];
int cnt = 0, fa[N], n, m, sum = 0;
int findset(int x)
{
if(x == fa[x]) return x;
else return fa[x] = findset(fa[x]);
}
int calc(int x, int y)
{
return (x - 1) * m + y;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n * m; ++ i) fa[i] = i;
int x, y, a, b;
while(scanf("%d", &x) != EOF)
{
scanf("%d %d %d", &y, &a, &b);
// printf("%d %d %d %d!\n", x, y, a, b);
x = findset(calc(x, y)), a = findset(calc(a, b));
fa[x] = a;
}
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= m; ++ j)
{
x = i + 1, y = j;
if(x >= 1 && y >= 1 && x <= n && y <= m && findset(calc(i, j)) != findset(calc(x, y)))
{
e[++ cnt] = ((edge){calc(i, j), calc(x, y), 1});
}
x = i, y = j + 1;
if(x >= 1 && y >= 1 && x <= n && y <= m && findset(calc(i, j)) != findset(calc(x, y)))
{
e[++ cnt] = ((edge){calc(i, j), calc(x, y), 2});
}
}
}
sort(e + 1, e + cnt + 1);
for (int i = 1; i <= cnt; ++ i)
{
x = findset(e[i].u), y = findset(e[i].v);
if(x == y) continue;
fa[x] = y;
sum += e[i].w;
}
int res = 0;
printf("%d", sum);
return 0;
}
新的开始
跟点扯上关系了,用Prim吧。
当年的我做这些题怎么这么困难呢。因为我压根没听懂最小生成树以及证明,现在怎么懂了呢,可能是......坚果吃少了
下雨了。
#include <bits/stdc++.h>
using namespace std;
const int N = 305, M = N * N;
int val[N][N], d[N], n, sum = 0;
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w; }
};
priority_queue<edge> q;
bool vis[N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i)
{
scanf("%d", &d[i]);
q.push((edge){i, d[i]});
}
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= n; ++ j) scanf("%d", &val[i][j]);
}
while(!q.empty())
{
int x = q.top().v; q.pop();
if(vis[x]) continue;
vis[x] = 1;
for (int y = 1; y <= n; ++ y)
{
if(x == y || vis[y]) continue;
if(d[y] > val[x][y])
{
d[y] = val[x][y];
q.push((edge){y, d[y]});
}
}
}
for (int i = 1; i <= n; ++ i) sum += d[i];
printf("%d", sum);
return 0;
}
北极通讯网络
建最小生成树,然后直接删除k - 1条最大的边,但是请注意,k <= 1的时候不能删边
#include <bits/stdc++.h>
using namespace std;
#define xx first
#define yy second
typedef double db;
const int N = 500 * 500 + 5;
struct edge
{
int u, v;
db w;
bool operator < (const edge &a) const {return w < a.w; }
}e[N], qwq[N];
int n, cnt = 0, k, fa[N], vis[N];
db ans = 0.0;
int findset(int x)
{
if(x == fa[x]) return x;
else return fa[x] = findset(fa[x]);
}
pair<db, db> p[505];
db calc(pair<db, db> a, pair<db, db> b)
{
return sqrt((a.xx - b.xx) * (a.xx - b.xx) + (a.yy - b.yy) * (a.yy - b.yy));
}
int main()
{
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; ++ i) scanf("%lf %lf", &p[i].xx, &p[i].yy);
for (int i = 1; i <= n; ++ i)
{
for (int j = i + 1; j <= n; ++ j)
{
e[++ cnt] = ((edge){i, j, calc(p[i], p[j])});
}
}
sort(e + 1, e + cnt + 1);
int sum = 0;
for (int i = 1; i <= n; ++ i) fa[i] = i;
for (int i = 1; i <= cnt; ++ i)
{
int x = findset(e[i].u), y = findset(e[i].v);
if(x == y) continue;
fa[x] = y;
sum ++, qwq[sum] = e[i];
if(sum == n - 1) break;
}
if(k >= 2) printf("%.2lf", qwq[sum - k + 1].w);
else printf("%.2lf", qwq[sum].w);
return 0;
}
走廊泼水节
#include <bits/stdc++.h>
using namespace std;
const int N = 6006;
int n, siz[N], fa[N];
int findset(int x)
{
if(fa[x] == x) return x;
return fa[x] = findset(fa[x]);
}
struct edge
{
int u, v, w;
bool operator < (const edge &a) const {return w < a.w; }
}e[N];
long long sum = 0;
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) fa[i] = i, siz[i] = 1;
for (int i = 1; i <= n - 1; ++ i) scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
sort(e + 1, e + n);
sum = 0;
for (int i = 1; i <= n - 1; ++ i)
{
int x = findset(e[i].u), y = findset(e[i].v);
if(x == y) continue;
sum = sum + (long long)(e[i].w + 1) * (siz[x] * siz[y] - 1);
fa[x] = y, siz[y] += siz[x];
}
printf("%lld\n", sum);
}
return 0;
}
秘密的牛奶运输
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 300005, N = 100005;
int n, m, fd[N];
ll mit = 0;
bool vis[M];
struct edge1
{
int u, v, w;
friend bool operator < (edge1 a, edge1 b) {return a.w < b.w; }
}p[M];
struct edge2
{
int v, w;
};
vector<edge2> g[N];
int findset(int x)
{
if(x == fd[x]) return x;
else return fd[x] = findset(fd[x]);
}
void kruskal()
{
for (int i = 1; i <= n; ++ i) fd[i] = i;
sort(p + 1, p + m + 1);
int sum = 0;
for (int i = 1; i <= m; ++ i)
{
int u = findset(p[i].u), v = findset(p[i].v);
if(u == v) continue;
g[p[i].u].push_back((edge2){p[i].v, p[i].w});
g[p[i].v].push_back((edge2){p[i].u, p[i].w});
fd[u] = v, vis[i] = true, sum ++;
mit += (ll)p[i].w;
if(sum == n - 1) break;
}
return ;
}
int f[N][18], dep[N], d1[N][18], d2[N][18], val[10];
void build_tree(int x, int fa)
{
dep[x] = dep[fa] + 1, f[x][0] = fa;
for (int i = 1; i <= 17; ++ i)
{
f[x][i] = f[f[x][i - 1]][i - 1];
val[0] = d1[x][i - 1], val[1] = d1[f[x][i - 1]][i - 1], val[2] = d2[x][i - 1], val[3] = d2[f[x][i - 1]][i - 1];
sort(val, val + 3 + 1);
d1[x][i] = val[3];
for (int j = 3; j >= 0; -- j) if(val[j] != val[3]) {d2[x][i] = val[j]; break;}
if(!f[x][i]) break;
}
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i].v, w = g[x][i].w;
if(y == fa) continue;
d1[y][0] = w;
build_tree(y, x);
}
return ;
}
int lca(int x, int y, int w)
{
if(dep[x] < dep[y]) swap(x, y);
int ans = 0;
for (int i = 17; i >= 0; -- i)
{
if(dep[f[x][i]] >= dep[y])
{
if(w == d1[x][i]) ans = max(ans, d2[x][i]);
else ans = max(ans, d1[x][i]);
x = f[x][i];
}
}
if(x == y) return ans;
for (int i = 17; i >= 0; -- i)
{
if(f[x][i] != f[y][i])
{
if(w == d1[x][i]) ans = max(ans, d2[x][i]);
else ans = max(ans, d1[x][i]);
if(w == d1[y][i]) ans = max(ans, d2[y][i]);
else ans = max(ans, d1[y][i]);
x = f[x][i], y = f[y][i];
}
}
if(w != d1[x][0]) ans = max(ans, d1[x][0]);
if(w != d1[y][0]) ans = max(ans, d1[y][0]);
return ans;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++ i) scanf("%d %d %d", &p[i].u, &p[i].v, &p[i].w);
kruskal();
build_tree(1, 0);
ll ans = 0x7f7f7f7f7f7f7f;
for (int i = 1; i <= m; ++ i)
{
if(!vis[i] && p[i].u != p[i].v)
{
int vlu = lca(p[i].u, p[i].v, p[i].w);
if(!vlu) continue;
ans = min(ans, mit - (ll)vlu + p[i].w);
}
}
printf("%lld", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!