最小生成树
kruskal
运用贪心的思想,每次将边权最小且两端点均未被标记的点加入,并将点标记,重复执行直到有 (n-1) 条边已选
#include<iostream>
#include<cstdio>
#include<math.h>
#include<cstring>
#include<algorithm>
#define ll long long
const ll maxn=2e5+10;
ll n,m,cnt,ans;
ll fa[maxn];
struct node
{
ll u,v,w;
} s[maxn];
inline bool cmp(node a,node b)
{
return a.w<b.w;
}
inline ll find(ll x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
inline void kruskal()
{
for(int i=1;i<=m;i++)
{
ll uu=s[i].u,vv=s[i].v;
ll eu=find(uu),ev=find(vv);
if(eu==ev) continue;
fa[ev]=eu;
ans+=s[i].w;
cnt++;
if(cnt==n-1) break;
}
}
int main(void)
{
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%lld %lld %lld",&s[i].u,&s[i].v,&s[i].w);
}
std::sort(s+1,s+m+1,cmp);
kruskal();
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(find(i)!=find(j))
{
printf("orz
");
return 0;
}
}
}
printf("%lld
",ans);
return 0;
}
prim
# include <cstring>
# include <cstdio>
# include <algorithm>
# include <iostream>
using namespace std;
# define N 1001
# define INF 0x3f3f3f3f
int A[N][N],dist[N];
bool vis[N];
int n,m,ans;
int prim(int root)
{
int x,ans=0;
memset(dist,0x3f,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[root]=0;
for(int i=1;i<=n;i++)
{
x=0;
for(int j=1;j<=n;j++)
if(!vis[j]&&(x==0||dist[j]<dist[x]))x=j;
vis[x]=true;
for(int y=1;y<=n;y++)
if(!vis[y])dist[y]=min(dist[y],A[x][y]);
}
for(int i=1;i<=n;i++)
{
if(dist[i]==INF)return INF;
ans+=dist[i];
}
return ans;
}
int main()
{
int x,y,z;
scanf("%d%d",&n,&m);
memset(A,0x3f,sizeof(A));
for(int i=1;i<=n;i++)A[i][i]=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
A[y][x]=A[x][y]=min(A[x][y],z);
}
int ans=prim(1);
if(ans==INF)puts("impossible");
else printf("%d
",ans);
return 0;
}
次小生成树
只需先求出一个最小生成树,然后将树边用次大的非树边依次尝试替换即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#define ll long long
using namespace std;
const ll INF=999999999999999;
const ll maxn=3e5+10;
ll n,m,cnt,ans,ans2=INF,flag;
ll fa[maxn],dep[maxn],vis[maxn],b[maxn];
ll f[maxn][30],g1[maxn][30],g2[maxn][30];
vector<pair<ll,ll> > e[maxn];
struct node
{
ll x,y,z;
} s[maxn];
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
inline ll find(ll x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
inline bool cmp(node a,node b)
{
return a.z<b.z;
}
inline void kruskal()
{
sort(s+1,s+m+1,cmp);
for(int i=1;i<=m;i++)
{
ll eu=find(s[i].x),ev=find(s[i].y);
if(eu==ev) continue;
ans+=s[i].z;
fa[ev]=eu;
e[s[i].y].push_back(make_pair(s[i].x,s[i].z));
e[s[i].x].push_back(make_pair(s[i].y,s[i].z));
b[i]=1;
}
}
inline void dfs(ll x,ll v)
{
f[x][0]=v;
for(int i=0;i<e[x].size();i++)
{
ll y=e[x][i].first;
if(y==v) continue;
dep[y]=dep[x]+1;
g1[y][0]=e[x][i].second;
g2[y][0]=-INF;
dfs(y,x);
}
}
inline void pre()
{
for(int i=1;i<=25;i++)
{
for(int j=1;j<=n;j++)
{
f[j][i]=f[f[j][i-1]][i-1];
g1[j][i]=max(g1[j][i-1],g1[f[j][i-1]][i-1]);
g2[j][i]=max(g2[j][i-1],g2[f[j][i-1]][i-1]);
if(g1[j][i-1]>g1[f[j][i-1]][i-1]) g2[j][i]=max(g2[j][i],g1[f[j][i-1]][i-1]);
else if(g1[j][i-1]<g1[f[j][i-1]][i-1]) g2[j][i]=max(g2[j][i],g1[j][i-1]);
}
}
}
inline ll LCA(ll p1,ll p2)
{
if(dep[p1]<dep[p2]) swap(p1,p2);
for(int i=25;i>=0;i--)
{
if(dep[f[p1][i]]>=dep[p2])
{
p1=f[p1][i];
}
}
if(p1==p2) return p2;
for(int i=25;i>=0;i--)
{
if(f[p1][i]!=f[p2][i])
{
p1=f[p1][i];
p2=f[p2][i];
}
}
return f[p1][0];
}
inline ll q_LCA(ll p1,ll p2,ll w)
{
ll sum=-INF;
for(int i=25;i>=0;i--)
{
if(dep[f[p1][i]]>=dep[p2])
{
if(w!=g1[p1][i]) sum=max(g1[p1][i],sum);
else sum=max(sum,g2[p1][i]);
p1=f[p1][i];
}
}
return sum;
}
int main(void)
{
n=read();
m=read();
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
s[i].x=read();s[i].y=read();s[i].z=read();
}
kruskal();
g2[1][0]=-INF;
dep[1]=1;
dfs(1,-1);
pre();
// printf("%lld
",ans);
for(int i=1;i<=m;i++)
{
if(!b[i])
{
ll mid=LCA(s[i].x,s[i].y);
ll QAQ=q_LCA(s[i].x,mid,s[i].z);
ll QWQ=q_LCA(s[i].y,mid,s[i].z);
ans2=min(ans2,ans-max(QAQ,QWQ)+s[i].z);
}
}
printf("%lld
",ans2);
return 0;
}