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

本文共 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

你可能感兴趣的文章
component-based scene model
查看>>
Echart输出图形
查看>>
hMailServer搭建简单邮件系统
查看>>
从零开始学习jQuery
查看>>
Spring+SpringMVC+MyBatis深入学习及搭建(四)——MyBatis输入映射与输出映射
查看>>
opacity半透明兼容ie8。。。。ie8半透明
查看>>
CDOJ_24 八球胜负
查看>>
Alpha 冲刺 (7/10)
查看>>
一款jQuery打造的具有多功能切换的幻灯片特效
查看>>
SNMP从入门到开发:进阶篇
查看>>
@ServletComponentScan ,@ComponentScan,@Configuration 解析
查看>>
unity3d 射弹基础案例代码分析
查看>>
thinksns 分页数据
查看>>
os模块
查看>>
LINQ to SQL vs. NHibernate
查看>>
基于Angular5和WebAPI的增删改查(一)
查看>>
windows 10 & Office 2016 安装
查看>>
最短路径(SP)问题相关算法与模板
查看>>
js算法之最常用的排序
查看>>
Python——交互式图形编程
查看>>