給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz。
對於乙個無向圖,要求選出一些邊,使得圖上的每乙個節點互相連通,且邊權和最小。選出的邊與節點形成的子圖必然是顆樹,這棵樹叫做最小生成樹。
最小生成樹中,除根節點外,每乙個節點作為乙個to節點與它相鄰的邊的邊權(以後簡稱最小相鄰邊權)必然是最小的。
像dijkstra一樣,用乙個priority_queue維護已訪問的邊,使得堆頂的邊的邊權是最小的。每次迴圈給出一條邊cur,如果cur->to節點不在樹中,則cur的權值便是cur->to的最小相鄰邊權。於是將cur->to節點納入樹中並記錄結果。然後,由to節點擴充套件與它相鄰的邊e(e->to也不在樹內)。
對於稠密圖,用鄰接表的方式還要維護乙個堆,時間太慢。所以定義lowlen[u]為u節點目前搜尋到的作為乙個to節點與它相鄰的邊的邊權的最小值。每次關於樹內邊的個數的cnt迴圈,將堆頂出來一條邊改為列舉每乙個不在樹內的節點,找出lowlen[u]最小的u,此時的lowlen[u]便是u最小相鄰邊權。於是將u納入樹中,記錄結果,然後通過u重新整理與它相鄰的樹外節點的lowlen。
#include #include #include #include #include //#define test#define loop(a, b) for(int a=1;(a)<=(b);a++)
using namespace std;
const int max_node = 5010, max_edge = 200010 * 2, inf = 0x3f3f3f3f;
struct prim
}_nodes[max_node];
int _vcount;
node *start;
struct edge
bool operator <(const edge a)const
}_edges[max_edge];
int _ecount;
void init(int vcount, int sid)
edge *newedge()
void addedge(node *from, node *to, int len)
void build(int uid, int vid, int len)
int proceed()
return cnt == _vcount ? ans : -1;
}}g;
struct primmatrix
void build(int u, int v, int dist)
int proceed()
}if (lowlen == inf)
break;
cnt++;
ans += lowlen;
intree[u] = true;
loop(v, _vcount)//注意從此往後就不用lowlen了。lowlen就是為了確定u用的。
if (!intree[v] && len[u][v] < lowlen[v])
lowlen[v] = len[u][v];
} return cnt == _vcount ? ans : -1;
}}g1;
int main()
int ans = g1.proceed();
if (ans == -1)
printf("orz\n");
else
printf("%d\n", ans);
return 0;
}
3366 模板 最小生成樹(Prim)
如題,給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz 輸入格式 第一行包含兩個整數n m,表示該圖共有n個結點和m條無向邊。n 5000,m 200000 接下來m行每行包含三個整數xi yi zi,表示有一條長度為zi的無向邊連線結點xi yi 輸出格式 輸出包含乙個數,即最小生成樹...
P3366 模板 最小生成樹
如題,給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz 輸入格式 第一行包含兩個整數n m,表示該圖共有n個結點和m條無向邊。n 5000,m 200000 接下來m行每行包含三個整數xi yi zi,表示有一條長度為zi的無向邊連線結點xi yi 輸出格式 輸出包含乙個數,即最小生成樹...
P3366 模板 最小生成樹
如題,給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz 輸入格式 第一行包含兩個整數n m,表示該圖共有n個結點和m條無向邊。n 5000,m 200000 接下來m行每行包含三個整數xi yi zi,表示有一條長度為zi的無向邊連線結點xi yi 輸出格式 輸出包含乙個數,即最小生成樹...