生成树(洛谷团队图论题)----本题出自同机房大佬

  • 题目描述
    给定一个无向图G,求
    Σ|from,to|(from+to)×ST(from,to)
    其中ST(from,to)表示包含[from,to]这条边的生成树中权值最小的生成树的权值。
  • 输入格式
    第一行有两个整数n,m,分别表示图的点数和边数。
    以下m行,每行有三个整数f,t,w,表示在f和t之间有一条权值为w的边。
  • 输出格式
    输出Σ|from,to|(from+to)×ST(from,to)
  • 输入样例
5 8
1 2 1
1 3 3
1 5 2
2 4 5
2 5 4
3 4 2
3 5 1
4 5 6
  • 输出样例
372
  • 说明/提示
    数据范围:1<=n<=100000,1<=v<=300保证图无自环,无重边。
  • 样例解释ST(1,2)=6
    ST(3,5)=6
    ST(1,5)=6
    ST(3,4)=6
    ST(1,3)=7
    ST(2,5)=8
    ST(2,4)=9
    ST(4,5)=10

啊啊啊啊啊啊啊啊啊啊
一中午都没做出来
首先:可以暴力试一试哎,直接将每个包含这条边的最小生成树做出来,一个个算就行了呗

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
struct edge{
    int a,b,d;
}e[200005];
bool cmp(edge a,edge b){return a.d<b.d;}
int n,m,f[100005],fin,tot,ans;
int find(int k){
    if(f[k]==k)return k;
    return f[k]=find(f[k]);
}
void merge(int a,int b){f[find(a)]=find(b);}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].d);
    sort(e,e+m,cmp);
    for(int i=0;i<m;i++){
        for(int j=1;j<=n;j++)f[j]=j;
        merge(e[i].a,e[i].b);
        tot=e[i].d;
        for(int j=0;j<m;j++){
            if(i!=j&&find(e[j].a)!=find(e[j].b)){
                merge(e[j].a,e[j].b);
                tot+=e[j].d;
            }
            fin=1;
            for(int k=1;k<n;k++)if(find(k)!=find(k+1)){fin=0;break;}
            if(fin)break;
        }
        ans+=tot*(e[i].a+e[i].b);
    }
    printf("%d",ans);
    return 0;
}

竟然还良心给了30分!!!


正解
先求一遍最小生成树,然后不在最小生成树上的边就去掉因它构成的环中的最大边

//c++11
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<tuple>
using namespace std;
int max_[100005][20],gr[100005][20],dep[100005],n,m,mst,f[100005];
long long ans;
struct graph_td{int to,dis;};
struct graph_ftd{int from,to,dis;}e[200005];
bool cmp(graph_ftd a,graph_ftd b){return a.dis<b.dis;}
vector<graph_td> gtd[100005];
set<tuple<int,int> >imst;
int find(int t){return t==f[t]?t:f[t]=find(f[t]);}
void add(int f,int t,int dis){
    gtd[f].push_back((graph_td){t,dis});
    gtd[t].push_back((graph_td){f,dis});
}
void merge(int a,int b){f[find(a)]=find(b);}
void dfs(int n){
    for(int i=gtd[n].size()-1;i>=0;i--){
        if(gtd[n][i].to==gr[n][0])continue;
        int t=gtd[n][i].to,w=gtd[n][i].dis;
        gr[t][0]=n;
        max_[t][0]=w;
        for(int i=1;i<17;i++)gr[t][i]=gr[gr[t][i-1]][i-1];
        for(int i=1;i<17;i++)max_[t][i]=max(max_[t][i-1],max_[gr[t][i-1]][i-1]);
        dep[t]=dep[n]+1;
        dfs(t);
    }
}
int lca(int a,int b){
    if(a==b)return 0;
    int res=0;
    if(dep[a]<dep[b])swap(a,b);
    for(int i=16;i>=0;i--)
        if(dep[gr[a][i]]>=dep[b])
            res=max(res,max_[a][i]),a=gr[a][i];
    if(a==b)return res;
    for(int i=16;i>=0;i--)
        if(gr[a][i]!=gr[b][i]){
            res=max(max(res,max_[a][i]),max_[b][i]);
            a=gr[a][i],b=gr[b][i]; 
        }
    return max(max(res,max_[a][0]),max_[b][0]);
}
int kruskal(){
    sort(e,e+m,cmp);
    for(int i=1;i<=n;i++)f[i]=i;
    int count=1,mst=0;
    for(int i=0;i<m;i++){
        if(count==n)break;
        int f=e[i].from,t=e[i].to,w=e[i].dis;
        if(find(f)==find(t))continue;
        count++;
        merge(f,t);
        add(f,t,w);
        imst.insert(make_tuple(f,t));
        mst+=w;
    }
    return mst;
}
void read(int &s){
    s=0;
    int w=1,c=getchar();
    while((c-8)/10-4){if(c=='-')w=-1;c=getchar();}
    while(!((c-8)/10-4))s=s*10+c-'0',c=getchar();
    s*=w;
}
int main(){
    read(n),read(m);
    for(int i=0,a,b,c;i<m;i++){
        read(a),read(b),read(c);
        e[i].from=a,e[i].to=b,e[i].dis=c;
    }
    mst=kruskal();
    dfs(1);
    for(int i=0,f,t,w;i<m;i++){
        f=e[i].from,t=e[i].to,w=e[i].dis;
        ans+=(long long)(f+t)*(imst.count(make_tuple(f,t))?mst:mst-lca(f,t)+w);
    }
    printf("%lld",ans);
}
发布了12 篇原创文章 · 获赞 14 · 访问量 553

猜你喜欢

转载自blog.csdn.net/Wonderful_Answer/article/details/103703593
今日推荐