1. 最小生成树之prim算法
算法简单描述
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
慢慢想想就很好理解(尤其是学过离散数学)就是一个点集,一个边集。 点集随便选一个点放进去, 边集置空。不断找和 点集 中的点 相连的权值最小的边的点(该点在点集外), 将该点放入点集, 该边放入边集。
直至这中放了n个点。
模板。
#define inf 0x3f3f3f
#define ms(x) memset(x, 0 ,sizeof(x))
const int N = 110;
int maze[N][N];
bool vis[N];
int lowc[N];
int Prim(int cost[][N], int n)
{
int ans = 0;
ms(vis);
vis[0] = true; // 将 0 加入点集
for(int i=1;i<n;i++) lowc[i] = cost[0][i]; //lowc[i] 记录终点未i的边的权值, 当前点集中只有0 所以找 cost[0][i]
for(int i=1;i<n;i++)
{
int mic = inf;
int p=-1;
for(int j=0;j<n;j++)
if(!vis[j] && mic>lowc[j])// 在点集之外寻找到点集里的点最短的边
{
mic = lowc[j];
p = j;
}
if(mic == inf) return -1; //如果无法找到更小的边 且未进行完n-1次, 即未取完n-1条边
ans+=mic; // 将取到的边的权值加入答案中
vis[p] = true; // 加入点集
for(int j=0;j<n;j++)
if(!vis[j] && lowc[j] > cost[p][j])
{
lowc[j] = cost[p][j]; //看能否更新到点集中的点的边权
}
}
return ans;
}
2.最小生成树之kruskal算法
1).记Graph中有v个顶点,e个边
2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
3).将原图Graph中所有e个边按权值从小到大排序
4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中
if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中
添加这条边到图Graphnew中
#define inf 0x3f3f3f3f
#define ms(x) memset(x, 0, sizeof(x))
#define mf(x) memset(x,-1, sizeof(x))
using namespace std;
const int N = 110; //点数
const int M = 100000; //边数
int f[N];
struct Edge{
int u, v, w;
}edge[M];
int tol;
void addedge(int u, int v, int w) //加边
{
edge[tol].u = u;
edge[tol].v = v;
edge[tol++].w = w;
}
bool cmp(Edge a, Edge b){ //边权从小到大排列。
return a.w < b.w;
}
int Find(int x) //用并查集判断联通分量
{
if(f[x] == -1) return x;
else return f[x] = Find(f[x]);
}
int Kruskal(int n)
{
mf(f);
sort(edge, edge+tol, cmp); //根据边权排序,这样就默认从最小的边开始选,如果边的两点不在同一个联通分量中
int cnt = 0; //即未被加到生成树上, 那么就把它俩合并。
int ans = 0;
for(int i=0;i<tol;i++)
{
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
int t1 = Find(u);
int t2 = Find(v);
if(t1 != t2)
{
ans += w;
f[t1] = t2;
cnt++;
}
if(cnt == n-1) break;
}
if(cnt<n-1) return -1;
else return ans;
}
int main()
{
int n, m;
while(cin>>n)
{
tol = 0;
scanf("%d", &m);
while(m--)
{
int u, v, w;
scanf("%d%d%d",&u, &v, &w);
addedge(u, v, w);
}
int ans = Kruskal(n);
printf("%d\n",ans);
}
return 0;
}