40pts求调,悬赏 1 关注
查看原帖
40pts求调,悬赏 1 关注
502758
ForMyDream楼主2023/1/10 18:05

#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 100005
#define INF 2147483647

// 两个结构体,前者用于存储所边,后者用于存储MST中的边 
struct AllEdge{
	int u,v,w;
	bool operator <(const AllEdge &r)const{
		return w<r.w;
	}
}a[maxn];
struct Edge{
	int v,w,nxt;
}edge[maxn<<1]; 
int n,m,pos,head[maxn],cnt,fa[maxn],sum;
// sum:最小生成树边权和 
int dep[maxn],f[maxn][21],g[maxn][20],h[maxn][20];
bool vis[maxn];

void add(int u,int v,int w){
	edge[++cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].nxt=head[u];
	head[u]=cnt;
}

void init(){
	cin>>n>>m;
	for (int i=1;i<=n;i++){
		fa[i]=i;
	}
	int u,v,w;
	for (int i=1;i<=m;i++){
		cin>>a[i].u>>a[i].v>>a[i].w;
	}
	sort(a+1,a+1+m);
}

int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}

void merge(int u,int v){
	fa[u]=v;
}

void kruskal(){
	int tot=0;
	int u,v,w,x,y;
	for (int i=1;i<=m;i++){
		u=a[i].u,v=a[i].v,w=a[i].w;
		x=find(u),y=find(v);
		if (x!=y){
			vis[i]=true;
			tot++; merge(x,y); sum+=w;
			add(u,v,w);add(v,u,w); // 加入最小生成树,进入edge数组 
			if (tot==n-1) break;
		}
	}
}

void dfs(int u,int fa,int w){
	// g[i][j]: i~i+2^j 的最大值 h[i][j]: i~i+2^j 的次大值 
	dep[u]=dep[fa]+1;
	f[u][0]=fa;
	g[u][0]=w;h[u][0]=-INF;
	for (int i=1;i<=20;i++){
		f[u][i]=f[f[u][i-1]][i-1];
		g[u][i]=max(g[u][i-1],g[f[u][i-1]][i-1]);
		h[u][i]=max(h[u][i-1],h[f[u][i-1]][i-1]);
		if (g[u][i-1]>g[f[u][i-1]][i-1]){
			h[u][i]=max(h[u][i],g[f[u][i-1]][i-1]);
		}
		else if (g[u][i-1]<g[f[u][i-1]][i-1]){
			h[u][i]=max(h[u][i],g[u][i-1]);
		}
	}
	for (int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].v,w=edge[i].w;
		if (v==fa) continue;
		dfs(v,u,w);
	}
}

int lca(int x,int y){
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=20;i>=0;i--){
		if (dep[f[x][i]]>=dep[y]){
			x=f[x][i];
		}
	}
	if (x==y) return x;
	for (int i=20;i>=0;i--){
		if (f[x][i]!=f[y][i]){
			x=f[x][i],y=f[y][i];
		}
	}
	return f[x][0];
}

int get(int u,int v,int mx,int ans=-INF){
	// 求这个环中的次大边 
	for (int i=20;i>=0;i--){
		if (dep[f[u][i]]>=dep[v]){
			if (mx!=g[u][i]){
				ans=max(ans,g[u][i]);
			}
			else ans=max(ans,h[u][i]);
			u=f[u][i];
		}
	}
	cout<<ans<<' ';
	return ans;
}

void output(int ans=INF){
	int u,v,w,l,x,y;
	for (int i=1;i<=m;i++){
		if (vis[i]) continue;
		u=a[i].u,v=a[i].v,w=a[i].w;
		l=lca(u,v),x=get(u,l,w),y=get(v,l,w);
		cout<<"lca"<<l<<' '; 
		ans=min(ans,sum-max(x,y)+w);
		cout<<u<<' '<<v<<' '<<w<<' '<<i<<' '<<ans<<endl; 
	}
//	for (int i=1;i<=m;i++){
//		if (vis[i]) continue;
//		u=a[i].u,v=a[i].v,w=a[i].w,l=lca(u,v);
//		x=get(u,l,w),y=get(v,l,w);
//		ans=min(ans,sum-max(x,y)+w);
//	}
	cout<<ans;
}

int main(){
	ios::sync_with_stdio(false); 
	init();
	kruskal();
//	cout<<sum<<endl;
	dfs(1,0,0);
	output();
	return 0;
} 

用的是倍增lca+Kruskal,悬赏1关注

2023/1/10 18:05
加载中...