欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

EOJ_1094_寻找航海路线

发布时间:2024/4/11 29 豆豆
生活随笔 收集整理的这篇文章主要介绍了 EOJ_1094_寻找航海路线 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
#include <iostream> #include <cstring> #define INF 0x3f3f3f3fusing namespace std;/*Prim算法需要的全局变量*/ bool visited [501]; int cost[501][501]; int pre[501]; int lowc[501]; /*Prim算法需要的全局变量*/ /*次小生成树需要的全局变量*/ bool used[501][501]; //标记边是否被用在最小生成树中 int max_edge[501][501]; //记录两个点之间最长的边的长度 /*次小生成树需要的全局变量*/int Prim(int n) {int total = 0, index;for(int i=2; i<=n; ++i){lowc[i] = cost[1][i];if(lowc[i]<INF)pre[i] = 1;}pre[1] = 0;visited[1] = true;for(int i=2; i<=n; ++i){int min_e = INF;for(int j=2; j<=n; ++j){if(!visited[j] && lowc[j]<min_e){min_e = lowc[j];index = j;}}total += lowc[index];visited[index] = true;used[index][pre[index]] = used[pre[index]][index] = true; //标记这条边用过了for(int j=2; j<=n; ++j){if(!visited[j] && cost[index][j]<lowc[j]){lowc[j] = cost[index][j];pre[j] = index;}if(visited[j] && j!=index) //更新最长边//这里其实是动态规划,假设2-3-4-5联通,求2-5中的最长边,//其实就是等价于2-3-4中的最长边与4-5边中的较大值//即max(max_edge(2-3-4),length(4-5))max_edge[index][j] = max_edge[j][index] = max(max_edge[pre[index]][j], lowc[index]);}}return total; }int second_st(int n, int MST) {int total = INF;/*遍历所有边*/for(int i=1; i<=n; ++i)for(int j=i+1; j<=n; ++j){if(!used[i][j] && cost[i][j]<INF)total = min(MST-max_edge[i][j]+cost[i][j], total);}if(total == INF) //找不到次小生成树total = -1;return total; }int main() {int N, M, u, v, w, MST, SMT;while(cin>>N>>M){memset(visited, 0, sizeof(visited));memset(max_edge, 0, sizeof(max_edge));memset(used, 0, sizeof(used));for(int i=1; i<=N; ++i)for(int j=1; j<=N; ++j)cost[i][j] = INF;for(int i=0; i<M; ++i){cin>>u>>v>>w;cost[u][v] = w;cost[v][u] = w;}MST = Prim(N);SMT = second_st(N, MST);cout<<MST<<' '<<SMT<<endl;}return 0; }

求次小生成树

定义:所有生成树中路径长是第二小的树
可行变换:一棵生成树换一条边仍然为生成树,称为进行了可行变换
临集:换了边的生成树 ∈\in 原来生成树的临集

  • 用定义,得到所有的生成树(spanning tree),路径总和排第二的就是次小生成树
  • 求得最小生成树后枚举n-1条边,循环n-1次,分别去掉第i(i ∈\in [1,n-1])条边后得到的最小生成树路径,用vector存储,取最小值即可
  • 根据“次小生成树一定在最小生成树的临集中”定理
  • 枚举要加入哪条新边(U-V),加入后会出现一条回路,因此删除的边必须是在MST上从u到v的路径上,而且是这条路径的最长边
  • 因为次小生成树的路径和与最小生成树的路径和之差等于加入的边与删除的边之差,
  • 即求MST外的一条边与边的端点间最长边长度之差
  • 再遍历所有MST外的边即可
  • 注意

  • prim 算法模板是用 lowc[i] = 0 表示点i 被选中
  • 在动态规划得到max_edge时注意lowc[j]此时为0
  • 即使在动态规划中解决了lowc[j]==0的问题(用一个tmpLostc暂时存储lowc[j]即可),我也没有成功计算出正确的max_edge,很怪
  • [参考]
    1.https://www.bilibili.com/video/BV1CC4y1a7kD?from=search&seid=17175123924411804815&spm_id_from=333.337.0.010.
    2.https://blog.csdn.net/CoolCoolCarrot/article/details/100675150?ops_request_misc=&request_id=&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2alles_rank~default-1-100675150.pc_search_es_clickV2&utm_term=%E5%AF%BB%E6%89%BE%E8%88%AA%E6%B5%B7%E8%B7%AF%E7%BA%BF&spm=1018.2226.3001.4187

    总结

    以上是生活随笔为你收集整理的EOJ_1094_寻找航海路线的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。