hihocoder 1109 堆优化的Prim算法

  题目链接:http://hihocoder.com/problemset/problem/1109 , 最小生成树 + 堆优化(优先队列)。

  可以用优先队列,也可以自己手动模拟堆,为了练手,我两种都试了下,优先队列还是要方便一点,不过堆要快一点。

  没有无缘无故的爱,也没有无缘无故减少的时间复杂度。所以,好好学算法。

 


堆优化的代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF 1e8
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = 2333333; 
const int maxn = 100000 + 5;
struct Edge {    //邻接表表示图
    int v , w;
    bool operator < (const Edge &tmp) const {
        return w < tmp.w;
    }
} a[maxn];
vector <Edge> e[maxn];
int vis[maxn] , dist[maxn];

void PushUp(int rt , int r)
{        //自下向上更新以rt为根,r为右边界的堆
    int i = r >> 1;
    while(i >= rt) {
        if(a[r] < a[i]) {
            swap(a[r] , a[i]);
            r = i;
            i >>= 1;
        } else {
            break;
        }
    }
}
void PushDown(int rt , int r)
{        //自上向下更新以rt为根,r为右边界的堆
    int i = rt << 1;
    while(i <= r) {
        if(a[i].w > a[i + 1].w)
            i++;
        if(a[i] < a[rt]) {
            swap(a[i] , a[rt]);
            rt = i;
            i <<= 1;
        } else {
            break;
        }
    }
}
int Prim(int s , int n)
{
    int tot , ans;    //tot表示堆中元素的个数
    tot = ans = 0;
    memset(vis , 0 , sizeof(vis));
    for(int i = 1 ; i <= n ; i++) 
        dist[i] = INF;
    a[++tot].v = s;
    a[tot].w = 0;
    while(tot >= 1) {
        Edge u = a[1];
        swap(a[1] , a[tot]);
        a[tot--].w = INF;
        PushDown(1 , tot);  
        if(vis[u.v])
            continue;
        ans += u.w;
        vis[u.v] = 1;
        for(int i = 0 ; i < e[u.v].size() ; i++) {
            int j = e[u.v][i].v;
            if(dist[j] > e[u.v][i].w) {
                dist[j] = e[u.v][i].w;
                if(!vis[j]) {
                    a[++tot] = e[u.v][i];
                    PushUp(1 , tot);
                }
            }
        }
    }
    return ans;
}
int main()
{
    int n , m , u , v , w;
    scanf("%d %d" , &n , &m);
    while(m--) {
        scanf("%d %d %d" , &u , &v , &w);
        Edge tmp = {v , w};
        e[u].push_back(tmp);
        tmp.v = u;
        e[v].push_back(tmp);
    }
    printf("%d
" , Prim(1 , n));
    return 0;
}

优先队列优化(注意重载运算符地方的细节):

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF 1e8
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = 2333333; 
const int maxn = 100000 + 5;
struct Edge {
    int v , w;
    bool operator < (const Edge &tmp) const {
        return w > tmp.w;
    }
} a[maxn];
vector <Edge> e[maxn];
int vis[maxn] , dist[maxn];

int Prim(Edge s , int n)
{
    priority_queue <Edge> que;
    int ans = 0;
    for(int i = 1 ; i <= n ; i++) {
        dist[i] = INF;
        vis[i] = 0;
    }
    que.push(s);
    while(!que.empty()) {
        Edge u = que.top();
        que.pop();
        if(vis[u.v])
            continue;
        vis[u.v] = 1;
        ans += u.w;
        for(int i = 0 ; i < e[u.v].size() ; i++) {
            int j = e[u.v][i].v;
            if(dist[j] > e[u.v][i].w && !vis[j]) {
                dist[j] = e[u.v][i].w;
                que.push(e[u.v][i]);
            }
        }
    }
    return ans;
}
int main()
{
    int n , m , u , v , w;
    scanf("%d %d" , &n , &m);
    while(m--) {
        scanf("%d %d %d" , &u , &v , &w);
        Edge tmp = {v , w};
        e[u].push_back(tmp);
        tmp.v = u;
        e[v].push_back(tmp);
    }
    Edge tmp = {1 , 0};
    printf("%d
" , Prim(tmp , n));
    return 0;
}
原文地址:https://www.cnblogs.com/H-Vking/p/4317009.html