最小生成树

局域网

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;
}
posted @   Helioca  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
Document
点击右上角即可分享
微信分享提示