蓝桥杯每日真题 - 第13天

题目:(删边问题)

题目描述(14届 C&C++ B组F题)

解题思路:

  • 图的构建:使用邻接链表表示图,边的起点和终点分别存储在数组中,以支持高效的遍历。

  • Tarjan算法:利用Tarjan算法找到割边(即桥),判断割边是否会将图分为两个连通分量。

  • 求解最小权值差:对于每条割边,计算割除后的两个连通分量的权值之差。遍历所有割边,求出权值差的最小值。

  • 结果输出:若找不到合法的删除方案(即不存在割边),输出-1;否则,输出最小权值差。

代码实现(C语言):

cs 复制代码
//建议先去学最短路劲生成(dijskra堆优化)和最小树生成(kruskal)后再来学tarjan算法
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//邻接链表
long long weight[200009];//点权
long long sum=0;//边权和
int end=0;
int head[2*200009];//每一个u对应的边的序号
int v[2*200009];//边从u到v
int next[2*200009];//前一个u起头的边

//tarjan
int dfn[200009];//节点u搜索的次序编号
int low[200009];//u或者u的子树能追寻的最早的栈中的节点序号
int index=0;//访问点的个数
int mark[200009];//记录该点是否被访问过
long long ans=9999999999;//最小差值

int N,M;//N个节点,M个边

long long min(long long a,long long b)
{
  if(a<b) return a;
  else return b;
}

void add(int U,int V)
{//建立邻接链表
  end++;
  v[end]=V;
  next[end]=head[U];
  head[U]=end;
}

void tarjan(int x,int ine)//追寻到点x,访问的路劲的对应边的编号
{
  dfn[x]=++index;
  low[x]=index;
  //遍历x能走的边
  for(int i=head[x];i;i=next[i])
  {
    int t=v[i];
    if(dfn[t]==0)//mark
    {//没被访问,向下进行访问,直到把x的强联通图访问完
      tarjan(t,i);
      //向下访问后,回溯的时候赋值
      //min判断交叉时每条路劲的值,从而得到最小值
      low[x]=min(low[t],low[x]);
      weight[x]+=weight[t];//联通路劲点权和
      if(low[t]>dfn[x])//t的分支最终没连上跟
      {
        //砍掉t的分支,t分支实现内循环,并找到最小差值
        ans=min(ans,llabs(sum-2*weight[t]));
      }
    }
    //给每一个联通到跟的点赋值
    else if(i!=ine-1&&i!=ine+1) low[x]=min(low[x],dfn[t]);
  }
}
int main(int argc, char *argv[])
{
  // 请在此输入您的代码
  scanf("%d%d",&N,&M);
  for(int i=1;i<=N;i++)
  {
    scanf("%lld",&weight[i]);
    sum+=weight[i];
  }
  for(int i=1;i<=M;i++)
  {
    int U,V;
    scanf("%d%d",&U,&V);
    add(U,V);
    add(V,U);
  }
  tarjan(1,0);
  if(weight[1]!=sum)//没有联通 
  printf("%lld",sum-2*weight[1]);
  else 
  {
    if(ans!=9999999999) printf("%lld",ans);
    else printf("-1");
  }
  return 0;
}

代码分析:

  • 图的构建:使用邻接链表结构存储图,以便高效遍历所有边。

  • Tarjan算法:通过DFS和low数组计算割边。Tarjan算法能够在一次DFS中找到所有割边,效率较高。

  • 最小差值计算:在找到的割边中,计算每条割边将图分成的两个连通分量的权值差,并更新最小差值。

  • 结果输出:若没有找到合法的割边,输出-1,否则输出最小差值。

得到运行结果:

难度分析

⭐️⭐️⭐️⭐️

总结

  • 该算法适用于解决无向图中的割边问题,并且能高效计算分割后的连通分量权值差。

  • Tarjan算法在一次深度优先搜索中找出割边,提高了效率,是处理连通分量问题的有效工具。

  • 代码逻辑较为复杂,尤其是在low和dfn数组的更新上,需要对图的割边和强连通分量有较好理解

相关推荐
小武编程1 分钟前
基于JL700N可视化SDK的MAC地址应用
c语言·tws耳机·杰理jl700n
乌萨奇也要立志学C++6 分钟前
【洛谷】BFS 求解最短路:从马的遍历到迷宫问题的实战解析
算法·宽度优先
mailangduoduo8 分钟前
零基础教学连接远程服务器部署项目——VScode版本
服务器·pytorch·vscode·深度学习·ssh·gpu算力
老鼠只爱大米15 分钟前
LeetCode经典算法面试题 #46:全排列(回溯、交换、剪枝等五种实现方案详细解析)
算法·leetcode·剪枝·回溯·全排列·stj算法
Dovis(誓平步青云)28 分钟前
《滑动窗口算法:从 “暴力遍历” 到 “线性高效” 的思维跃迁》
运维·服务器·数据库·算法
_OP_CHEN1 小时前
【算法基础篇】(五十七)线性代数之矩阵乘法从入门到实战:手撕模板 + 真题详解
线性代数·算法·矩阵·蓝桥杯·c/c++·矩阵乘法·acm/icpc
天天爱吃肉82181 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
im_AMBER1 小时前
Leetcode 114 链表中的下一个更大节点 | 删除排序链表中的重复元素 II
算法·leetcode
凉、介1 小时前
VMware 三种网络模式(桥接 / NAT / Host-Only)原理与实验解析
c语言·网络·笔记·操作系统·嵌入式·vmware
xhbaitxl1 小时前
算法学习day38-动态规划
学习·算法·动态规划