[次小生成树] Prime Kruskal

Prime

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define MAXINT 2147483647/2
using namespace std;

int a,b,w,n,m,t,tot,ntot=MAXINT;
int e[5001][5001],flag[5001],pre[5000],dis[5001];
int maxd[5000][5000];

inline int Prim(int vi)
{
	for (int j=1;j<=n;j++)
	    if (e[vi][j]!=0) dis[j]=e[vi][j],pre[j]=vi;
	        else dis[j]=MAXINT;
	flag[vi]=1; dis[vi]=0;
	for (int i=1;i<n;i++)
    {
    	int min=MAXINT,mink;
    	for (int j=1;j<=n;j++)
    	    if (!flag[j] && dis[j]<min)
    	        min=dis[j],mink=j;
    	for (int j=1;j<=n;j++)
    	    if (flag[j])
			    maxd[j][mink]=maxd[mink][j]=max(min,maxd[pre[mink]][j]);
    	flag[mink]=1;
    	for (int j=1;j<=n;j++)
    	    if (!flag[j] && e[mink][j]!=0 && e[mink][j]<dis[j])
    	        dis[j]=e[mink][j],pre[j]=mink;	
    }
    for (int j=1;j<=n;j++)
        tot+=dis[j];
}


int main()
{
	scanf("%d%d",&n,&m);	
	for (int i=1;i<=m;i++)
	    scanf("%d%d%d",&a,&b,&w),e[a][b]=w,e[b][a]=w;
	Prim(1);
	printf("%d\n",tot);
	for (int i=1;i<=n;i++)
	    for (int j=i+1;j<=n;j++)
	        if (e[i][j]!=0 && i!=pre[j] && j!=pre[i])
	            if (tot-maxd[i][j]+e[i][j]<ntot)
	                ntot=tot-maxd[i][j]+e[i][j];
	printf("%d\n",ntot);
	return 0;
}

/*
9 15
1 2 10
2 3 18
3 4 22
4 5 20
5 6 26
6 1 11
2 7 16
6 7 17
3 9 8
9 4 21
2 9 12
7 4 24
8 4 16
8 5 7
7 8 19


99
101
*/


Kruskal

BZOJ 1977

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#define V G[p].v
#define oo 1<<30
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

struct edge{
	int u,v,w;
	int next;
};

edge G[200005];
int head[100005],num=1;

inline void add(int u,int v,int w,int p)
{
	G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

inline void link(int u,int v,int w)
{
	add(u,v,w,++num); add(v,u,w,++num);
}

struct Edge{
	int u,v,w;
	int flag;
	bool operator < (const Edge &B) const{
		return w<B.w;
	}
}E[300005];

int n,m;
ll tot,ans;
int fat[100005];

inline int getfat(int u)
{
	if (u==fat[u]) return u; 
	return fat[u]=getfat(fat[u]);
}

inline void Kru()
{
	int fx,fy;
	for (int i=1;i<=n;i++) fat[i]=i;
	for (int i=1;i<=m;i++)
	{
		fx=getfat(E[i].u),fy=getfat(E[i].v);
		if (fx!=fy)
		{
			E[i].flag=1;
			fat[fx]=fy;
			link(E[i].u,E[i].v,E[i].w);
			tot+=E[i].w;
		}
	}
}

struct data{
	int a,b;
	data(int _a=-oo,int _b=-oo):a(_a),b(_b) { }
};

data operator + (data A,data B)
{
	data ret;
	if (A.a>B.a)
		ret.a=A.a,ret.b=max(A.b,B.a);
	else
		ret.a=B.a,ret.b=max(A.a,B.b);
	return ret;
}

int depth[100005],parent[100005][20];
data mum[100005][20];

inline void dfs(int u,int fa)
{
	parent[u][0]=fa; depth[u]=depth[fa]+1;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
		{
			dfs(V,u);
			mum[V][0]=data(G[p].w,-oo);
		}
}

inline void Pre()
{
	for (int k=1;k<=18;k++)
		for (int i=1;i<=n;i++)
		{
			parent[i][k]=parent[parent[i][k-1]][k-1];
			mum[i][k]=mum[i][k-1]+mum[parent[i][k-1]][k-1];
		}
}

inline int LCA(int u,int v)
{
	if (depth[u]<depth[v]) swap(u,v);
	for (int k=18;k>=0;k--)
		if (((depth[u]-depth[v])>>k)&1) 
			u=parent[u][k];
	if (u==v) return u;
	for (int k=18;k>=0;k--)
		if (parent[u][k]!=parent[v][k])
			u=parent[u][k],v=parent[v][k];
	return parent[u][0];
}

inline data calc(int u,int v)
{
	int lca=LCA(u,v),d;
	data ret;
	d=depth[u]-depth[lca];
	for (int k=0;k<=18;k++)
		if ((d>>k)&1)
			ret=ret+mum[u][k],u=parent[u][k];
	d=depth[v]-depth[lca];
	for (int k=0;k<=18;k++)
		if ((d>>k)&1)
			ret=ret+mum[v][k],v=parent[v][k];
	return ret;
}

int main()
{
	data ret;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(m);
	for (int i=1;i<=m;i++)
		read(E[i].u),read(E[i].v),read(E[i].w);
	sort(E+1,E+m+1);
	Kru();
	mum[1][0]=data(-oo,-oo); dfs(1,0);
	Pre();
	ans=1LL<<60;
	for (int i=1;i<=m;i++)
		if (!E[i].flag)
		{
			ret=calc(E[i].u,E[i].v);
			if (ret.a==E[i].w && ret.b!=1<<30)
				ans=min(ans,tot-ret.b+E[i].w);
			else if (ret.a!=1<<30)
				ans=min(ans,tot-ret.a+E[i].w);
		}
	cout<<ans<<endl;
	return 0;
}


核心思想是断开一条边,连上一条替换,使权值增加

你可能感兴趣的:([次小生成树] Prime Kruskal)