次小生成树

在这里插入图片描述在这里插入图片描述在这里插入图片描述
**解题报告:**这还是个定理吧,就是说我们可以删掉最小生成树的一条树边,然后加上该点的树边,就能形成一个生成树,(如上图p2,绿色的边是两个点之间的最长树边,我们可以把他删掉,加上蓝色的边,这样并不影响它的连通性,所以他还是生成树)那么就一定有他的值是sum-l+w,为了让这个值最小并且比sum大,sum指的是最小生成树所有和,那么一定要找到a,b之间的最大树边(a,b指的是w边的两个顶点),这个可以dfs做,然而这样并不一样对,看上图p3,墨染空大佬就指出了一个错误,当两点之间的距离如果等于这条边,在原做法里面就不会更新了,然而我们可以更新次大值,不得不说是真的强啊。当然在dfs的时候,我们要注意,不要直接用maxd和maxd2,要用两个变量次次存放这两条边,因为在不同邻边下,条件是不一样的,同时更新次大值的时候,注意是严格次大值(就是不能和最大值相等)。

#include<bits/stdc++.h>
using namespace std;
const   int N = 510, M=10010;
typedef long long ll;
int dist[N][N];
int dist2[N][N];
int n,m;
int h[N],e[N*2],w[N*2],idx,ne[N*2];
int p[N];
struct node{
    int a;
    int b;
    int w;
    bool f;
    bool operator <(const node&W) const
    {
        return w<W.w;
    }
}q[M];
int find(int x)
{
    if(x!=p[x])
    p[x] = find(p[x]);
    return p[x];
    
}
void add(int a,int b,int c)
{
    w[idx] = c ,ne[idx]=h[a], e[idx] = b ,h[a]= idx++;
}
void dfs(int u,int fa,int maxd,int maxd2,int d[],int d2[])
{
    d[u] = maxd;
    d2[u] = maxd2;
    for(int i=h[u];~i;i=ne[i])
    {
        int t1=maxd;
        int t2 = maxd2;
        int j=e[i];
        if(j==fa)   continue;
        if(w[i]>t1)  t2=t1,t1 = w[i];
        else if(w[i]<t1&&w[i]>t2) t2 = w[i];
        dfs(j,u,t1,t2,d,d2);
    }
}
int main()
{
    cin >> n >> m;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        q[i]={a,b,c};
    }
    sort(q,q+m);
    for(int i=1;i<=n;i++)
    p[i] = i;
    ll sum=0;
    memset(h,-1,sizeof h);
    for(int i=0;i<m;i++)
    {
        int pa = find(q[i].a) , pb = find(q[i].b) , c = q[i].w;
        int a=q[i].a,b=q[i].b;
        if(pa!= pb)
        {
            sum += c;
            p[pa] =  pb;
            add(a,b,c);
            add(b,a,c);
            q[i].f=true;
        }
    }
    for(int i=1;i<=n;i++)   dfs(i,-1,0,-1e9,dist[i],dist2[i]);
    ll res = 1e18;
    for(int i=0;i<m;i++)
    {
        if(!q[i].f)
        {       
       int a = q[i].a , b=q[i].b ,c  =q[i].w;
        if(c>dist[a][b])
        {
            res = min(res,sum-dist[a][b]+c);
        }
        else if(c>dist2[a][b])
        res = min(res,sum-dist2[a][b]+c);
        }
    }
    cout << res <<endl;
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值