//kruskal struct EDGE{ LL u,v,w; }edge[200000+5]; LL n,m,ans,eu,ev,cnt=0; LL fa[5000+5]; inline bool cmp(EDGE a,EDGE b){ return a.w<b.w; } inline LL find(LL x) { while(x!=fa[x]) x=fa[x]=fa[fa[x]]; return x; } inline void kruskal() { sort(edge+1,edge+m+1,cmp); for(register int i=1;i<=m;i++) { eu=find(edge[i].u) , ev=find(edge[i].v); if(eu == ev) continue ; ans += edge[i].w ; fa[ev]=eu; if(++cnt == n-1) break ; } return ; }
kruskal是按權值排序的貪心算法ios
衆所周知 n個點 靠n-1條邊就能夠連通了。。c++
帶上權值 就能夠連成一棵最小生成樹。算法
prim的話數組
prim的話 有好幾種版本。。優化
#include<cstdio> #include<cstdlib> #include<iostream>
using namespace std; /*最小生成樹Prim未優化版*/
int book[100];//用於記錄這個點有沒有被訪問過
int dis[100];//用於記錄距離樹的距離最短路程
int MAX = 99999;//邊界值
int maps[100][100];//用於記錄全部邊的關係
int main() { int i,j,k;//循環變量
int n,m;//輸入的N個點,和M條邊
int x,y,z;//輸入變量
int min,minIndex; int sum=0;//記錄最後的答案
cin>>n>>m; //初始化maps,除了本身到本身是0其餘都是邊界值
for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { if(i!=j) maps[i][j] = MAX; else maps[i][j] = 0; } } for (i = 1; i <= m; i++) { cin>>x>>y>>z;//輸入的爲無向圖
maps[x][y] = z; maps[y][x] = z; } //初始化距離數組,默認先把離1點最近的找出來放好
for (i = 1; i <= n; i++) dis[i] = maps[1][i]; book[1]=1;//記錄1已經被訪問過了
for (i = 1; i <= n-1; i++)//1已經訪問過了,因此循環n-1次
{ min = MAX;//對於最小值賦值,其實這裏也應該對minIndex進行賦值,可是咱們認可這個圖必定有最小生成樹並且不存在兩條相同的邊 //尋找離樹最近的點
for (j = 1; j <= n; j++) { if(book[j] ==0 && dis[j] < min) { min = dis[j]; minIndex = j; } } //記錄這個點已經被訪問過了
book[minIndex] = 1; sum += dis[minIndex]; for (j = 1; j <= n; j++) { //若是這點沒有被訪問過,並且這個點到任意一點的距離比如今到樹的距離近那麼更新
if(book[j] == 0 && maps[minIndex][j] < dis[j]) dis[j] = maps[minIndex][j]; } } cout<<sum<<endl; }
#include<bits/stdc++.h>//鏈式前向星優化
using namespace std; #define re register
#define il inline il int read() { re int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x*f; }//快讀,不理解的同窗用cin代替便可
#define inf 123456789
#define maxn 5005
#define maxm 200005
struct edge { int v,w,next; }e[maxm<<1]; //注意是無向圖,開兩倍數組
int head[maxn],dis[maxn],cnt,n,m,tot,now=1,ans; //已經加入最小生成樹的的點到沒有加入的點的最短距離,好比說1和2號節點已經加入了最小生成樹,那麼dis[3]就等於min(1->3,2->3)
bool vis[maxn]; //鏈式前向星加邊
il void add(int u,int v,int w) { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } //讀入數據
il void init() { n=read(),m=read(); for(re int i=1,u,v,w;i<=m;++i) { u=read(),v=read(),w=read(); add(u,v,w),add(v,u,w); } } il int prim() { //先把dis數組附爲極大值
for(re int i=2;i<=n;++i) { dis[i]=inf; } //這裏要注意重邊,因此要用到min
for(re int i=head[1];i;i=e[i].next) { dis[e[i].v]=min(dis[e[i].v],e[i].w); } while(++tot<n)//最小生成樹邊數等於點數-1
{ re int minn=inf;//把minn置爲極大值
vis[now]=1;//標記點已經走過 //枚舉每個沒有使用的點 //找出最小值做爲新邊 //注意這裏不是枚舉now點的全部連邊,而是1~n
for(re int i=1;i<=n;++i) { if(!vis[i]&&minn>dis[i]) { minn=dis[i]; now=i; } } ans+=minn; //枚舉now的全部連邊,更新dis數組
for(re int i=head[now];i;i=e[i].next) { re int v=e[i].v; if(dis[v]>e[i].w&&!vis[v]) { dis[v]=e[i].w; } } } return ans; } int main() { init(); printf("%d",prim()); return 0; }
#include<cstdio>//堆優化版的prim #include<queue> #include<cstring> #include<algorithm>
#define R register int
using namespace std; int k,n,m,cnt,sum,ai,bi,ci,head[5005],dis[5005],vis[5005]; struct Edge { int v,w,next; }e[400005]; void add(int u,int v,int w) { e[++k].v=v; e[k].w=w; e[k].next=head[u]; head[u]=k; } typedef pair <int,int> pii; priority_queue <pii,vector<pii>,greater<pii> > q; void prim() { dis[1]=0; q.push(make_pair(0,1)); while(!q.empty()&&cnt<n) { int d=q.top().first,u=q.top().second; q.pop(); if(vis[u]) continue; cnt++; sum+=d; vis[u]=1; for(R i=head[u];i!=-1;i=e[i].next) if(e[i].w<dis[e[i].v]) dis[e[i].v]=e[i].w,q.push(make_pair(dis[e[i].v],e[i].v)); } } int main() { memset(dis,127,sizeof(dis)); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(R i=1;i<=m;i++) { scanf("%d%d%d",&ai,&bi,&ci); add(ai,bi,ci); add(bi,ai,ci); } prim(); if (cnt==n)printf("%d",sum); else printf("orz"); }
prim不如kruskal 若是說要是稠密圖【比較少的吧】spa
就用primcode
其實prim的優化挺快的吧blog
emm排序