A题:走廊泼水节

链接:https://ac.nowcoder.com/acm/contest/1056/A

题目描述

给定一棵N个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树。

求增加的边的权值总和最小是多少。

输入描述:

第一行包含整数t,表示共有t组测试数据。
对于每组测试数据,第一行包含整数N。
接下来N-1行,每行三个整数X,Y,Z,表示X节点与Y节点之间存在一条边,长度为Z。

输出描述:

每组数据输出一个整数,表示权值总和最小值。

每个结果占一行。

示例1

输入

2
3
1 2 2
1 3 3
4
1 2 3
2 3 4
3 4 5

输出

4
17

备注:

\[N <= 6000 , Z <= 100
\]

例解释

第一组数据,在 22 和 33 之间修建一条长度为 44 的道路,

使这棵树变成一个完全图,且原来的树依然是这个图的唯一最小生成树.

 

题解

  • 对给定树上的 \(N−1\) 条边模拟一遍\(Kruskal\)
  • 通过边$(x,y) $合并两个并查集
  • xx 集合中的每个点到 \(y\) 集合中的每个点
  • 添加一条长度为 $w(x,y)+1 $的边

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 6010
struct edge{ int u,v,w; }e[maxn];
int t,n,f[6010],s[6010];
long long ans;
bool cmp(edge x,edge y){ return x.w<y.w; }
int find(int x){
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;++i){ f[i]=i; s[i]=1; }
for(int i=1;i<n;++i) scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
sort(e+1,e+n,cmp);
ans=0;
for(int fu,fv,i=1;i<n;++i){
fu=find(e[i].u); fv=find(e[i].v);
if(fu==fv) continue;
ans+=1ll*(e[i].w+1)*(s[fu]*s[fv]-1);
f[fu]=fv;
s[fv]+=s[fu];
}
printf("%lld\n",ans);
}
return 0;
}

B题:Picnic Planning (控制度数的最小生成树,DFS)

https://ac.nowcoder.com/acm/contest/1056/B

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_Bstdio(false);cin.tie(0); cout.tie(0)
typedef long long ll; inline int read() {
int s = 0, w = 1; char ch = getchar();
while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
const int N = 37;
const int INF = 0x3f3f3f3f;
struct Edge {
int x, y, z;
bool operator < (const Edge w) const {
return z < w.z;
}
}f[N];
int n, k, tot, ans, a[N][N], fa[N], d[N], v[N];
map<string, int> mp;
vector<Edge> e;
bool b[N][N]; int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
} void dfs(int x, int pre) {
for (int i = 2; i <= tot; ++i) {
if (i == pre || !b[x][i]) continue;
if (f[i].z == -1) {
if (f[x].z > a[x][i]) f[i] = f[x];
else {
f[i].x = x;
f[i].y = i;
f[i].z = a[x][i];
}
}
dfs(i, x);
}
} int main() {
js;
memset(a, 0x3f, sizeof(a));
memset(d, 0x3f, sizeof(d));
mp["Park"] = tot = 1;
for (int i = 1; i < N; ++i) fa[i] = i;
cin >> n;
for (int i = 1; i <= n; ++i) {
Edge w;
string s1, s2;
cin >> s1 >> s2 >> w.z;
w.x = mp[s1] ? mp[s1] : (mp[s1] = ++tot);
w.y = mp[s2] ? mp[s2] : (mp[s2] = ++tot);
e.push_back(w);
a[w.x][w.y] = a[w.y][w.x] = min(a[w.x][w.y], w.z);
}
cin >> k;
sort(e.begin(), e.end());
for (auto it : e) { //去掉1的连边,构成几个连通块,再把连通块并成一个求解花费
if (it.x == 1 || it.y == 1) continue;
int fax = find(it.x), fay = find(it.y);
if (fax != fay) {
fa[fax] = fay;
b[it.x][it.y] = b[it.y][it.x] = 1;
ans += it.z;
}
}
for (int i = 2; i <= tot; ++i) //找连通区域内和1连接花费最小
if (a[1][i] != INF) {
int rt = find(i);
if (d[rt] > a[1][i]) {
v[rt] = i;
d[rt] = a[1][v[rt]];
}
}
for (int i = 1; i <= tot; ++i) { //先把连通区域和1连接
if (d[i] != INF) {
--k;
b[1][v[i]] = b[v[i]][1] = 1;
ans += a[1][v[i]];
}
}
while (k--) { //调整看能不能更小一点
memset(f, -1, sizeof(f));
f[1].z = -INF;
for (int i = 2; i <= tot; ++i)
if (b[1][i]) f[i].z = -INF;
dfs(1, 0);
int o, w = -INF;
for (int i = 2; i <= tot; ++i)
if (w < f[i].z - a[1][i]) {
o = i;
w = f[i].z - a[1][o];
}
if (w <= 0) break;
b[1][o] = b[o][1] = 1;
b[f[o].x][f[o].y] = b[f[o].y][f[o].x] = 0;
ans -= w;
}
cout << "Total miles driven: " << ans << endl;
return 0;
}

C题:最优比率生成树

https://ac.nowcoder.com/acm/contest/1056/C

0/1 规划问题,利用二分 + prim求解。

根据0/1问题模型,只需要构建一张新的无向网,图的结构不变,但每条边只有一个权值 \(C_e - mid * R_e\) ,在新的无向图中求解最大生成树,若最大生成树上边权之和非负,$l = mid $,否则令 \(r = mid\)。

#include<bits/stdc++.h>
using namespace std;
#define dis(a,b) sqrt(pow((nod[a].x - nod[b].x), 2) + pow((nod[a].y - nod[b].y), 2))
const int maxn = 5000;
const int inf = 0x3f3f3f3f;
struct node {
double x, y, c;
}nod[maxn];
int n;
double cost[maxn][maxn];
double a[maxn][maxn];
bool book[maxn];
double d[maxn]; double prim(double mid) {
memset(book, 0, sizeof(book));
for (int i = 1; i <= n; i++)
d[i] = 1e8;
d[1] = 0;
for (int i = 1; i < n; i++) {//一共只需要进行n-1次操作
int x = 0;
for (int j = 1; j <= n; j++)
if (!book[j] && (x == 0 || d[x] > d[j]))//找出没有用过或者距离已选遍最近的点
x = j;
book[x] = true;
for (int y = 1; y <= n; y++)
if (!book[y])d[y] = min(d[y], a[x][y] - mid * cost[x][y]);
}
double ans = 0.0;
for (int i = 2; i <= n; i++) {
ans += d[i];
}
return ans;
} int main() {
//freopen("in.txt", "r", stdin);
//ios::sync_with_stdio(false), cin.tie(0);
while (scanf("%d", &n), n) {
for (int i = 1; i <= n; i++)
scanf("%lf%lf%lf", &nod[i].x, &nod[i].y, &nod[i].c); for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
cost[i][j] = dis(i, j);
a[i][j] = fabs(nod[i].c - nod[j].c);
} double r = inf, l = 0;
while (r - l > 0.000001) {
double mid = (l + r) / 2;
double ans = prim(mid);
if (ans == 0)
break;
else if (ans > 0)
l = mid;
else
r = mid;
}
printf("%.3lf\n", (r + l) / 2);
}
}

D题:黑暗城堡 (最短路径生成树)

先跑一次dijkstra

对于构造一个树的过程,每个节点都会选择一个节点插入树中

只需要统计每个点能够选择哪些点(满足到1号点距离最小)去插入即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int e[maxn][maxn],inf=1e9;
int dis[maxn],vis[maxn];
const int mod=(1LL<<31)-1;
struct node
{
int s,id;
bool operator < (const node& b) const{
return (this->s)<b.s;
}
}q[maxn];
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++)
e[i][j]=e[j][i]=inf;
}
for(int i=1;i<=m;i++){
int t1,t2,t3;
scanf("%d%d%d",&t1,&t2,&t3);e[t1][t2]=e[t2][t1]=t3;
}
for(int i=1;i<=n;i++) dis[i]=inf;
dis[1]=0;
for(int i=1;i<n;i++){
int u,mx=1e9;
for(int j=1;j<=n;j++){
if(vis[j]) continue;
if(dis[j]<mx){
u=j;mx=dis[j];
}
}
vis[u]=1;
for(int j=1;j<=n;j++){
if(dis[j]>dis[u]+e[u][j]){
dis[j]=dis[u]+e[u][j];
}
}
}
for(int i=1;i<=n;i++){
q[i].s=dis[i];q[i].id=i;
}
sort(q+1,q+1+n);int ans=1;
for(int i=2;i<=n;i++){
int cnt=0;
for(int j=1;j<=n;j++){
if(j==i) continue;
if(dis[i]==dis[j]+e[j][i]) cnt++;
}
//cout<<i<<" "<<cnt<<endl;
ans=1LL*ans*cnt%mod;
}
cout<<ans<<endl;
}

0x62 图论-最小生成树的更多相关文章

  1. 图论-最小生成树<Kruskal>

    昨天: 图论-最小生成树<Dijkstra,Floyd> 以上是昨天的Blog,有需要者请先阅读完以上再阅读今天的Blog. 可能今天的有点乱,好好理理,认真看完相信你会懂得 然而,文中提 ...

  2. Light OJ 1029- Civil and Evil Engineer (图论-最小生成树)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1029 题目大意:一个发电站,给n座房子供电, 任意房子之间有电线直接或者间接相 ...

  3. Applese 的毒气炸弹 G 牛客寒假算法基础集训营4(图论+最小生成树)

    链接:https://ac.nowcoder.com/acm/contest/330/G来源:牛客网 Applese 的毒气炸弹 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262 ...

  4. 图论——最小生成树prim+邻接表+堆优化

    今天学长对比了最小生成树最快速的求法不管是稠密图还是稀疏图,prim+邻接表+堆优化都能得到一个很不错的速度,所以参考学长的代码打出了下列代码,make_pair还不是很会,大体理解的意思是可以同时绑 ...

  5. 图论——最小生成树_prim

    今天是最小生成树的prim的算法,因为本人水平有限所以堆优化都不是很会啊,但邻接表好像出了点小差错所以上邻接矩阵比较好一点,尽管比Kruskal慢了很多很多但这种贪心思想还是要学习的.从第一条边开始取 ...

  6. 图论-最小生成树-Kruskal算法

    有关概念: 最小生成树:在连通图G中,连接图G所有顶点且总权最小的边构成的树 思路: 首先对边按权从小到大排序,紧接着枚举每一条边,如果两个结点的祖先结点不同(并查集),则连上此边,直到边数等于结点数 ...

  7. 数据结构之 图论---最小生成树(prim + kruskal)

    图结构练习——最小生成树 Time Limit: 1000MS Memory limit: 65536K 题目描述  有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的.现在我们想知 ...

  8. 图论——最小生成树:Prim算法及优化、Kruskal算法,及时间复杂度比较

    最小生成树: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.简单来说就是有且仅有n个点n-1条边的连通图. 而最小生成树就是最小权 ...

  9. 【uva 1151】Buy or Build(图论--最小生成树+二进制枚举状态)

    题意:平面上有N个点(1≤N≤1000),若要新建边,费用是2点的欧几里德距离的平方.另外还有Q个套餐,每个套餐里的点互相联通,总费用为Ci.问让所有N个点连通的最小费用.(2组数据的输出之间要求有换 ...

  10. 图论---最小生成树----普利姆(Prim)算法

    普利姆(Prim)算法 1. 最小生成树(又名:最小权重生成树) 概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树.最小生成树属于一种树形结构(树形结构是一 ...

随机推荐

  1. 【uniapp】【外包杯】学习笔记day07 | 微信小程序轮播图、分类导航、楼层图的开发与实现

    1.创建home分支 2.配置网络请求 由于平台的限制,现需要建立uni-app中使用第三方包请求网络数据请求 在 uni-app 项目中使用 @escook/request-miniprogram  ...

  2. Linux下通过AnySetup配置防火墙

    软件 AnySetup 主要功能 主要功能是对Linux操作系统下的基本配置进行管理.多种服务配置进行管理.安全配置进行管理等.如:操作系统的升级管理,软件包的安装.更新和卸载管理,软件仓库源的管理, ...

  3. 关于mac电脑突然搜不到家里wifi但手机却能连上的问题解决

    今天用mac电脑时,突然遇到一个奇怪的问题,家里wifi用的好好的,突然就连不上了,在看电脑能搜索到的wifi,居然家里的wifi都没有搜索到,但自己的手机却是正常的,然后我再看看我另外一台windo ...

  4. 连续无创式血压估算cNIBP

    参考来源:ADI官网技术文章.知乎(hxl695822705.埃微许伯.Paddington.Lonerpaul.政聪.KingPo-张超.啪啦钉子.深圳加1健康科技) 参考文献:基于单路PPG信号的 ...

  5. Unicode编码解码

    一.Unicode概述 Unicode是一种字符编码标准,旨在解决不同字符集之间的兼容性问题.它为全球所有语言提供了一种统一的编码方式,使得各种字符能够在计算机系统中正确显示和处理.Unicode字符 ...

  6. jvm总结图解

    浅析jvm  内存模型 https://www.cnblogs.com/lewis0077/p/5143268.html

  7. CodeForces - 764C

    C. Timofey and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standa ...

  8. mybatis测试类的书写步骤

    mybatis测试类的书写步骤 private SqlSession session; @Test //* 1.根据UserMapper接口的Class对象获取Mapper接口类型的对象 //* 2. ...

  9. SpringBoot-MybatisPlus-Dynamic(多数据源)-springboot-mybatisplus-dynamic-duo-shu-ju-yuan-

    title: SpringBoot-MybatisPlus-Dynamic(多数据源) date: 2021-05-07 13:58:06.637 updated: 2021-12-26 17:43: ...

  10. vue3 + element-plus 的 upload + axios + django 文件上传并保存

    之前在网上搜了好多教程,一直没有找到合适自己的,要么只有前端部分没有后端,要么就是写的不是很明白.所以还得靠自己摸索出来后,来此记录一下整个过程. 其实就是不要用默认的 action,要手动实现上传方 ...