一道好題不出所料又抄的題解
1.首先對於這張圖肯定要考慮走哪些邊不走哪些邊,發現我們想要的肯定那些邊權最大的邊,所以想到最大生成樹
這樣能保證選到盡量大的邊
2.跑完最大生成樹后每兩點之間就有唯一路徑了,想要知道兩點間最小邊權,可以在LCA過程中求出(我竟然不會LCA),對lca做些許改動
#include<bits/stdc++.h> using namespace std; const int maxn=10010; const int maxm=50010; struct node1{ int u,v,w; }e1[maxm]; struct node2{ int v,w,nxt; }e2[maxm*2]; int head[maxn],cnt; int n,m; int dep[maxn],f[maxn],fa[maxn][21],w[maxn][21]; //f数组表示并查集中的父节点,fa数组表示树上的父节点,w数组表示最大载重 bool v[maxn]; void add(int u,int v,int w){ e2[++cnt].v=v;e2[cnt].w=w;e2[cnt].nxt=head[u];head[u]=cnt; } bool cmp(node1 x,node1 y){ return x.w>y.w; } int find(int x){ while(x!=f[x])x=f[x]=f[f[x]];return x; } void kruskal(){ sort(e1+1,e1+1+m,cmp); for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++){ int x=find(e1[i].u),y=find(e1[i].v); if(x==y)continue; f[x]=y; add(e1[i].u,e1[i].v,e1[i].w); add(e1[i].v,e1[i].u,e1[i].w); } } void dfs(int x){ v[x]=1; for(int i=head[x];i;i=e2[i].nxt){ int y=e2[i].v; if(v[y])continue; dep[y]=dep[x]+1; fa[y][0]=x;//儲存父節點 w[y][0]=e2[i].w; dfs(y); } } int lca(int x,int y){//lca過程中求邊權最小值 if(find(x)!=find(y))return -1;//不連通 int ans=0x7fffffff; if(dep[x]>dep[y])swap(x,y); //將y節點提升到x相同高度 for(int i=20;i>=0;i--) if(dep[fa[y][i]]>=dep[x]) ans=min(ans,w[y][i]),y=fa[y][i]; if(x==y)return ans; for(int i=20;i>=0;i--) if(fa[x][i]!=fa[y][i]){ ans=min(ans,min(w[x][i],w[y][i])); x=fa[x][i];y=fa[y][i]; } ans=min(ans,min(w[x][0],w[y][0])); return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d%d%d",&e1[i].u,&e1[i].v,&e1[i].w); kruskal(); for(int i=1;i<=n;i++) if(!v[i]){ dep[i]=1; dfs(i); fa[i][0]=i; w[i][0]=0x7fffffff; } //lca初始化 for(int i=1;i<=20;i++) for(int j=1;j<=n;j++){ fa[j][i]=fa[fa[j][i-1]][i-1]; w[j][i]=min(w[j][i-1],w[fa[j][i-1]][i-1]); } int q; scanf("%d",&q); while(q--){ int x,y; scanf("%d%d",&x,&y); printf("%d ",lca(x,y)); } }