删边最小生成树

删边最小生成树

时间限制: 1 Sec 内存限制: 128 MBnode

题目描述

给定一个n个点m条边的无向图,求删除某条以后的最小生成树。c++

输入

第一行两个整数n和m。
接下来m行,每行3个整数a、b、c
表示有条边链接编号为a和b的节点。web

输出

输出m行,每行一个整数。
表示若是第i条删除,最小生成树的大小,若是最小生成树不存在,输出-1。svg

样例输入

5 5
1 2 1
2 3 2
1 4 3
2 4 5
4 5 4spa

样例输出

14
-1
12
10
-1code

提示

30%的数据,n的范围[1,100],m的范围[1,1000];
50%的数据,n的范围[1,300],m的范围[1,3000];
80%的数据,n的范围[1,5000],m的范围[1,50000];
100%的数据,n的范围[1,50000],m的范围[1,200000],边权范围[1,40000];xml

暴力枚举blog

int find(int x){
    if(x==par[x])return x;
    return par[x]=find(par[x]);
}
void check(int x){
    int res=n,sum=0;
    for(int i=1;i<=n;i++)par[i]=i;
    for(int i=1;i<=m&&res!=1;i++){
        if(i==x)continue;
        a=s[i].a,c=s[i].c,b=s[i].b;
        fa=find(a),fb=find(b);
        if(fa==fb)continue;
        par[fa]=fb;sum+=c;res--;
    }ans[s[x].id]=res==1?sum:-1;
}
void solve(){   
    sort(s+1,s+1+m,cmp);
    for(int i=1;i<=m;i++){
        if(!mark[s[i].id])ans[s[i].id]=pro_sum;
        else check(i);
    }
}

思路

对于树而言它是无环的
这里写图片描述
若是加上一条边nw它就造成了一个环
对于环上的任意的一条边删去其中之一它仍为树图片

即nw能够代替该环上的任意边
那么对于最小生成树而言删去它的代价即为val[x]-val[nw];
因此删能够更新环上任意一条边的答案
显然加入的边要从小到大同时有答案的边无需更新内存

首先生成最小生成树

void made(){
    sort(E+1,E+1+m,cmp);
    int res=n,a,b,c,id,fa,fb;
    for(int i=1;i<=m&&res!=1;i++){
        a=E[i].a;b=E[i].b;
        c=E[i].c;id=E[i].id;
        fa=find(a);fb=find(b);
        if(fa==fb)continue;
        G[a].push_back((P){b,c,id});
        G[b].push_back((P){a,c,id});
        //生成最小生成树
        sum+=c;res--;
        par[fa]=fb;mark[id]=1;
    }d[1]=1;
    dfs(1);
}

那么如何遍历环呢?;
先预处理出因此的节点的父节点以及其对应的边的边号和代价

void dfs(int x){
    for(int i=0;i<G[x].size();i++){
        to=G[x][i].t;c=G[x][i].c;id=G[x][i].id;
        if(!d[to]){
            d[to]=d[x]+1;
            f[to]=x;dfs(to);
            td[to]=id;tc[to]=c;//记录该节点对应的边的id和c
        }
    }
}

从a,b节点来向上更新每一条边到LCA
这里写图片描述

void update(int a,int b){
    if(d[a]>d[b])swap(a,b);
    while(d[a]<d[b]){
        id=td[b];c=tc[b];//从节点获取对应的边的id和c
        if(!use[id])ans[id]=sum-c+cost,use[id]=1;
        b=f[b];
    }while(a!=b){
        //一直遍历到LCA(a,b);
        id=td[b];c=tc[b];
        if(!use[id])ans[id]=sum-c+cost,use[id]=1;
        b=f[b];
        id=td[a];c=tc[a];
        if(!use[id])ans[id]=sum-c+cost,use[id]=1;
        a=f[a];
    }
}
void solve(){
    for(int i=1;i<=m;i++)
    if(!mark[E[i].id]){
        a=E[i].a;b=E[i].b;c=E[i].c;
        cost=c;update(a,b);
    }for(int i=1;i<=m;i++){
        if(!mark[i])printf("%d\n",sum);
        else printf("%d\n",ans[i]);
    }return 0;
}

综上;

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
const int M=50005;
struct node{int a,b,c,id;}E[M*4];
struct P{int t,c,id;};
bool cmp(node x,node y){return x.c<y.c;}
vector<P>G[M];
int par[M],f[M],n,m,sum,d[M];
int td[M],tc[M],cost,ans[4*M];
bool mark[4*M],use[4*M];
int find(int x){
    if(x==par[x])return x;
    return par[x]=find(par[x]);
}
void dfs(int x){
    int to,c,id;
    for(int i=0;i<G[x].size();i++){
        to=G[x][i].t;
        c=G[x][i].c;
        id=G[x][i].id;
        if(!d[to]){
            d[to]=d[x]+1;
            td[to]=id;tc[to]=c;
            f[to]=x;
            dfs(to);
        }
    }
}
void update(int a,int b){
    int id,c;
    if(d[a]>d[b])swap(a,b);
    while(d[a]<d[b]){
        id=td[b];c=tc[b];
        if(!use[id])ans[id]=sum-c+cost,use[id]=1;
        b=f[b];
    }while(a!=b){
        id=td[b];c=tc[b];
        if(!use[id])ans[id]=sum-c+cost,use[id]=1;
        b=f[b];
        id=td[a];c=tc[a];
        if(!use[id])ans[id]=sum-c+cost,use[id]=1;
        a=f[a];
    }
}
void made(){
    sort(E+1,E+1+m,cmp);
    int res=n,a,b,c,id,fa,fb;
    for(int i=1;i<=m&&res!=1;i++){
        a=E[i].a;b=E[i].b;
        c=E[i].c;id=E[i].id;
        fa=find(a);fb=find(b);
        if(fa==fb)continue;
        G[a].push_back((P){b,c,id});
        G[b].push_back((P){a,c,id});
        sum+=c;res--;
        par[fa]=fb;mark[id]=1;
    }d[1]=1;
    dfs(1);
}
int main(){
    int a,b,c,id;
    memset(ans,-1,sizeof(ans));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a,&b,&c);   
        E[i]=(node){a,b,c,i};
    }
    for(int i=1;i<=n;i++)par[i]=i;
    made();
    for(int i=1;i<=m;i++)
    if(!mark[E[i].id]){
        a=E[i].a;b=E[i].b;c=E[i].c;
        cost=c;update(a,b);
    }for(int i=1;i<=m;i++){
        if(!mark[i])printf("%d\n",sum);
        else printf("%d\n",ans[i]);
    }return 0;
}