最小生成树(大纲,待补全)

最小生成树

最小生成树 - OI Wiki

前置知识

生成树

最小生成树

Prim

不常用(又不如kruskal快又不如kruskal好写),了解即可

思路类似dijkstra

以下为我也不知道我啥时候写出来的代码

邻接矩阵版本

#include <bits/stdc++.h>
using namespace std;
int n, m;
int t[5001][5001];
int d[5001];
bool vis[5001];
int ans, cnt;
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            t[i][j] = 1000000005;
        t[i][i] = 0;
    }
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        t[v][u] = t[u][v] = min(t[u][v], w);
    }
    for (int i = 1; i <= n; i++)
    {
        d[i] = 1000000005;
    }
    for (int i = 1; i <= n; i++)
    {
        d[i] = t[1][i];
    }
    d[1] = 0;
    vis[1] = 1;
    while (cnt <= n - 1)
    {
        int mini = 0, mind = 1000000005;
        for (int i = 1; i <= n; i++)
        {
            if (!vis[i] && d[i] < mind)
            {
                mind = d[i];
                mini = i;
            }
        }
        if (mini == 0)
        {
            break;
        }
        cnt++;
        ans += mind;
        d[mini] = 0;
        vis[mini] = 1;
        for (int i = 1; i <= n; i++)
        {
            d[i] = min(d[i], t[mini][i]);
        }
    }
    if (cnt == n - 1)
    {
        cout << ans << endl;
    }
    else
    {
        cout << -1 << endl;
    }
}

邻接表版本

#include <bits/stdc++.h>
using namespace std;
int n, m;
int fir[200001], to[1000001], nxt[1000001], dis[1000001], ecnt;
void add(int u, int v, int w)
{
    to[++ecnt] = v;
    dis[ecnt] = w;
    nxt[ecnt] = fir[u];
    fir[u] = ecnt;
}
int d[200001];
bool vis[200001];
int cnt;
long long ans;
struct node
{
    int x, d;
    node(int x, int d) : x(x), d(d) {}
};
bool operator<(node a, node b)
{
    return a.d > b.d;
}
priority_queue<node> q;
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
        add(v, u, w);
    }
    for (int i = 1; i <= n; i++)
        d[i] = 1000000005;
    q.push(node(1, 0));
    d[1] = 0;
    cnt = -1;
    while (!q.empty() && cnt < n - 1)
    {
        node h = q.top();
        q.pop();
        if (vis[h.x])
            continue;
        vis[h.x] = 1;
        d[h.x] = 0;
        cnt++;
        ans += h.d;
        for (int e = fir[h.x]; e; e = nxt[e])
        {
            if (d[to[e]] > dis[e])
            {
                d[to[e]] = dis[e];
                q.push(node(to[e], d[to[e]]));
            }
        }
    }
    if (cnt == n - 1)
    {
        cout << ans << endl;
    }
    else
    {
        cout << "orz" << endl;
    }
}

Kruskal

思想:贪心

每次找一条最短的边往生成树里加

正确性

Kruskal 证明 - OI Wiki

待补充

代码

#include<bits/stdc++.h>
using namespace std;
struct edge{
    int from,to,dis;
}g[500001];
bool cmp(edge a,edge b){
    return a.dis<b.dis;
}
int fa[200001];
int getf(int x){
    if(fa[x]==x)return x;
    fa[x]=getf(fa[x]);
    return fa[x];
}
int n,m,cnt;
long long ans;
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>g[i].from>>g[i].to>>g[i].dis;
    }
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    sort(g+1,g+m+1,cmp);
    for(int i=1;i<=m&&cnt<n-1;i++){
        int fu=getf(g[i].from),fv=getf(g[i].to);
        if(fu==fv)continue;
        fa[fu]=fv;
        cnt++;
        ans+=g[i].dis;
    }
    if(cnt==n-1){
        cout<<ans<<endl;
    }else{
        cout<<"orz";
    }
}

讲到的题

U69308 【常数PK系列】 #3 最小生成树

P1550 [USACO08OCT]Watering Hole G

P1536 村村通

P1396 营救

[P2820 局域网](https://www.luogu.com.cn/problem/P2820

posted @ 2020-04-11 11:13  water_lift  阅读(141)  评论(0编辑  收藏  举报