- 题目描述
给定一个无向图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);
}