博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UVA 10462 Is There A Second Way Left?(次小生成树&Prim&Kruskal)题解
阅读量:5769 次
发布时间:2019-06-18

本文共 3513 字,大约阅读时间需要 11 分钟。

 

思路:

Prim:

这道题目中有重边

Prim可以先加一个sec数组来保存重边的次小边,这样不会影响到最小生成树,在算次小生成树时要同时判断次小边(不需判断是否在MST中)

Kruskal:

Kruskal对重边就很友好了,不用考虑

原理是这样的:我们先找最小生成树并用used标记好哪些边是MST的边,然后我们暴力遍历每一条MST边被删去的情况,如果还能生成MST就找出这些MST最小的,这棵MST就是次小生成树

 

Prim代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int N = 200+5;const int INF = 0x3f3f3f3f;using namespace std;int n,m,p[N],Case = 1;int mp[N][N],sec[N][N],dis[N],x[N],y[N];int pre[N];bool vis[N];int Max[N][N]; //最大权值边bool is[N][N]; //是否在MST中void init(){ int a,b,c; scanf("%d%d",&n,&m); memset(mp,INF,sizeof(mp)); memset(sec,INF,sizeof(sec)); for(int i = 1;i <= m;i++){ scanf("%d%d%d",&a,&b,&c); if(c < mp[a][b]){ sec[a][b] = sec[b][a] = min(mp[a][b],sec[a][b]); //保存次小边 mp[a][b] = mp[b][a] = c; } else{ sec[a][b] = sec[b][a] = min(c,sec[a][b]); } } memset(vis,false,sizeof(vis)); vis[1] = true; for(int i = 2;i <= n;i++){ dis[i] = mp[i][1]; pre[i] = 1; }}void Prim(){ int mincost = 0; memset(Max,0,sizeof(Max)); memset(is,false,sizeof(is)); for(int i = 1;i <= n - 1;i++){ int MIN = INF; int point = -1; for(int j = 1;j <= n;j++){ if(!vis[j] && dis[j] < MIN){ MIN = dis[j]; point = j; } } if(point == -1){ printf("Case #%d : No way\n",Case++); return; } vis[point] = true; mincost += MIN; is[point][pre[point]] = is[pre[point]][point] = true; for(int j = 1;j <= n;j++){ if(vis[j] && j != point){ Max[j][point] = Max[point][j] = max(Max[pre[point]][j],dis[point]); } if(!vis[j] && dis[j] > mp[j][point]){ pre[j] = point; dis[j] = mp[j][point]; } } } int seccost = INF,flag = 0; for(int i = 1;i <= n;i++){ for(int j = 1;j < i;j++){ if(mp[i][j] != INF && !is[i][j]){ flag = 1; seccost = min(seccost,mincost - Max[i][j] + mp[i][j]); } if(sec[i][j] != INF){ flag = 1; seccost = min(seccost,mincost - Max[i][j] + sec[i][j]); } } } if(!flag) printf("Case #%d : No second way\n",Case++); else printf("Case #%d : %d\n",Case++,seccost);}int main() { int T; scanf("%d",&T); while(T--){ init(); Prim(); } return 0;}

Kruskal代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int N = 200+5;const int INF = 0x3f3f3f3f;using namespace std;struct edge{ int u,v,w;}e[N];bool cmp(edge a,edge b){ return a.w < b.w;}int f[N],used[N];int Case = 1;int Find(int x){ return f[x] == x? x : f[x] = Find(f[x]);}void Kruskal(){ int n,m,a,b,c; scanf("%d%d",&n,&m); for(int i = 1;i <= m;i++){ scanf("%d%d%d",&a,&b,&c); e[i].u = a; e[i].v = b; e[i].w = c; } sort(e+1,e+m+1,cmp); for(int i = 0;i <= n;i++) f[i] = i; int cnt = 0,tot = 0; for(int i = 1;i <= m;i++){ int fx = Find(e[i].u); int fy = Find(e[i].v); if(fx != fy){ f[fx] = fy; cnt++; used[tot++] = i; } if(cnt == n - 1) break; } if(cnt < n - 1){ printf("Case #%d : No way\n",Case++); return; } //次小生成树 int seccost = INF; for(int i = 0;i < tot;i++){ for(int j = 0;j <= n;j++) f[j] = j; int num = 0,cost = 0; for(int j = 1;j <= m;j++){ if(j == used[i]) continue; //删边 int fx = Find(e[j].u); int fy = Find(e[j].v); if(fx != fy){ f[fx] = fy; num++; cost += e[j].w; } if(num == n - 1) break; } if(num == n-1) seccost = min(seccost,cost); } if(seccost == INF) printf("Case #%d : No second way\n",Case++); else printf("Case #%d : %d\n",Case++,seccost);}int main() { int T; scanf("%d",&T); while(T--){ Kruskal(); } return 0;}

转载于:https://www.cnblogs.com/KirinSB/p/9408778.html

你可能感兴趣的文章
2012年电信业八大发展趋势
查看>>
Web日志安全分析工具 v2.0发布
查看>>
JS重载
查看>>
python2和python3同安装在Windows上,切换问题
查看>>
php加速工具xcache的安装与使用(基于LNMP环境)
查看>>
android超链接
查看>>
redhat tomcat
查看>>
统计数据库大小
查看>>
IO流的学习--文件夹下文件的复制
查看>>
第十六章:脚本化HTTP
查看>>
EXCEL表中如何让数值变成万元或亿元
查看>>
Cisco PIX防火墙的安装流程
查看>>
配置系列:ssm中applicationContext-mybatis.xml的简单配置
查看>>
mysql或者mariadb备份脚本
查看>>
extundelete恢复文件
查看>>
电池温度检测原理和示例代码
查看>>
Linux服务器性能评估与优化、监控利器---dstat应用
查看>>
hdu 2842 Chinese Rings 矩阵快速幂
查看>>
Powershell进阶学习(4) Powershell强大的利器“管道”
查看>>
关于GNU GPL
查看>>