最小生成樹 PRIM KRUSKAL
阿新 • • 發佈:2019-01-23
SDUT 2144
與此題為例講一下prim演算法
簡要概括最短路和最小生成樹的區別
一句話概括:最小生成樹是計算從一節點到另一節點的最小邊集;最短路是帶權路徑,計算權值最小。也就是說,最小生成樹要經過每一個點,而最短路只需要能達到某兩點,路徑權值最小即可!(這句話摘自其他部落格)
prim的演算法內容和最短路的DJ演算法差不多
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int tu[105][105];
int vis[105];
int mincost[105];//標記最小權值
int n;
int prim()
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++)//初始化從一開始到每個點的距離所以小於等於n
{
mincost[i]=tu[1][i];
}
vis[1]=1;
int ans=0;
for(int i=2; i<=n; i++)//找剩餘的n-1個點
{
int pos=i;
int M=INF;
for(int j=1; j<=n; j++)
{
if (!vis[j]&&mincost[j]<M)
{
M=mincost[j];
pos=j;
}
}
ans+=M;
vis[pos]=1;
for(int j=1; j<=n; j++)//鬆弛//更新從當前點到每個點的最短距離
{
if(!vis[j]&&mincost[j]>tu[pos][j])
{
mincost[j]=tu[pos][j];
}
}
}
return ans;
}
int main()
{
int m,j,k,l;
while(~scanf("%d %d",&n,&m))//n為點數,m為邊數
{
for(int i=1; i<=n; i++)//圖的預處理
for(int u=1; u<=n; u++)
i==u?tu[i][u]=1:tu[i][u]=INF;
for(int i=0; i<m; i++)//邊數
{
scanf("%d %d %d",&j,&k,&l);//無向圖
if(tu[j][k]>l)
{
tu[j][k]=l;
tu[k][j]=l;
}
}
int x=prim();
printf("%d\n",x);
}
}
SDUT 2144
依舊是這道題目講一下kruskal
kruskal可以運用了並查集,,不懂得去學吧(但是如果你都開始做這類題了,並查集沒理由不會啊)
#include <bits/stdc++.h>
using namespace std;
struct node
{
int u,v,w;
}tu[10005];
int p[1004],n,m;
bool cmp(node a,node b)
{
return a.w<b.w;
}
int fing(int x)//找大哥
{
return p[x]==x?x:p[x]=fing(p[x]);
}
void kruskal()
{
int ans=0;
int cnt=0;
for(int i=1;i<=n;i++)//初始化並茶几陣列,以點為下標所以為點數n
p[i]=i;
for(int i=1;i<=m;i++)//按邊生成
{
int x=fing(tu[i].u),y=fing(tu[i].v);
if(x!=y)
{
p[x]=y;
ans+=tu[i].w;
cnt++;
if(cnt==n)//所有點都走完了退出
break;
}
}
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
for(int i=1; i<=m; i++)//俺邊數輸入
{
scanf("%d %d %d",&tu[i].u,&tu[i].v,&tu[i].w);
}
sort(tu+1,tu+m+1,cmp);//kruskal按照邊權的大小來查詢最小邊權
kruskal();
}
}