目录
C:POJ-2031 Building a Space Station
图的几个基础概念
连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图。
强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向图为强连通图。
连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权;权代表着连接连个顶点的代价,称这种连通图叫做连通网。
生成树:一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。
最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。
Kruskal算法(参考最小生成树)
算法思想
此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
1. 把图中的所有边按代价从小到大排序;
2. 把图中的n个顶点看成独立的n棵树组成的森林;
3. 按权值从小到大选择边,所选的边连接的两个顶点ui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。
模板
struct node
{
int s,e,w;
}a[500];
int fa[30];
int n,m;
int Find(int x)
{
if(x==fa[x])
return x;
return fa[x]=Find(fa[x]);
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
int Kruskal()
{
sort(a,a+m,cmp);
int ans=0;
for(int i=0;i<n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
{
int fx=Find(a[i].s);
int fy=Find(a[i].e);
if(fx!=fy)
{
ans+=a[i].w;
fa[fx]=fy;
}
}
return ans;
}
Prim算法
算法思想
Prim算法的每一步都会为一棵生长中的树添加一条边。一开始这棵树只有一个顶点,然后会向它添加V-1条边,每次总是将下一条连接树中的顶点与不在树中的顶点且权重最小的边加入树中。
模板
int Prime()
{
for(int i=0; i<n; i++)
{
dis[i]=a[0][i];
vis[i]=false;
}
dis[0]=0;
vis[0]=true;
int ans=0;
for(int i=0; i<n-1; i++)
{
int p=-1;
int minn=INF;
for(int j=0; j<n; j++)
{
if(!vis[j]&&dis[j]<minn)
minn=dis[p=j];
}
ans+=minn;
vis[p]=true;
for(int j=1; j<n; j++)
{
if(!vis[j]&&dis[j]>a[p][j])
dis[j]=a[p][j];
}
}
return ans;
}
例题
A.POJ-1251 Jungle Roads:一道简单的模板题,AC代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
struct node
{
int s,e,w;
}a[500];
int fa[30];
int n,m;
int Find(int x)
{
if(x==fa[x])
return x;
return fa[x]=Find(fa[x]);
}
bool cmp(node a,node b)
{
return a.w<b.w;
}
int Kruskal()
{
sort(a,a+m,cmp);
int ans=0;
for(int i=0;i<n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
{
int fx=Find(a[i].s);
int fy=Find(a[i].e);
if(fx!=fy)
{
ans+=a[i].w;
fa[fx]=fy;
}
}
return ans;
}
int main()
{
while(cin>>n,n)
{
int x,y;
char ch1,ch2;
m=0;
for(int i=1;i<n;i++)
{