POJ(1258):Agri-Net(最小生成树)

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 68523   Accepted: 28406

Description

Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course. 
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms. 
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm. 
The distance between any two farms will not exceed 100,000. 

Input

The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.

Output

For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.

Sample Input

4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0

Sample Output

28

Source

USACO 102

图节点数目为N,正在构造的生成树为T,
• 维护Dist数组,Dist[i]表示Vi到T的“距离”
• 开始所有Dist[i] = 无穷大, T 为空集
1) 若|T| = N,最小生成树完成。否则取Dist[i]最小
的不在T中的点Vi, 将其加入T
2) 更新所有与Vi有边相连且不在T中的点Vj的Dist值:
Dist[j] = min(Dist[j],W(Vi,Vj))
3) 转到1)

                            关键问题
每次如何从连接T 中和T 外顶点的所有边中,找到一条最短的
1) 如果用邻接矩阵存放图,而且选取最短边的时候遍历所有点进行选取,则总时间复杂度为O(V 2 ), V 为顶点个数
2)用邻接表存放图,并使用堆来选取最短边,则总时间复杂度为O(ElogV)不加堆优化的Prim 算法适用

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
const int inf = 1<<30;

using namespace std;

struct edge{
    int v;
    int w;
    edge(int v_ = 0,int w_ = inf):v(v_),w(w_){}
    bool operator<(const edge &e)const{
        return w > e.w;
    }
};
vector<vector<edge> >G(110);

int heap_prime(const vector<vector<edge> >&G,int n){
    edge xDist(0,0);
    priority_queue<edge>pq;//存放顶点及其到在建生成树的距离
    vector<int>vDist(n);//各定点到已建好的那部分树的距离
    vector<int>vUsed(n);
    int nDoneNum = 0;
    for(int i = 0;i < n;i++){
        vUsed[i] = 0;
        vDist[i] = inf;
    }
    nDoneNum = 0;
    int nTotalW = 0;
    pq.push(edge(0,0));
    while(nDoneNum < n && !pq.empty()){
        do{
            xDist = pq.top();
            pq.pop();
        }while(vUsed[xDist.v]==1 && !pq.empty());
        if(vUsed[xDist.v] == 0){
            nTotalW += xDist.w;
            vUsed[xDist.v] = 1;
            nDoneNum++;
        }
        for(int i = 0;i < G[xDist.v].size();i++){
            int k = G[xDist.v][i].v;
            if(vUsed[k] ==0 ){
                int w = G[xDist.v][i].w;
//                    cout<<vDist[k]<<" "<<endl;
                    pq.push(edge(k,w));
            }
        }
    }
    if( nDoneNum < n )
    return -1; //图不连通
    return nTotalW;
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        for(int i = 0;i < n;i++)
            G[i].clear();
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                int w;
                scanf("%d",&w);
                G[i].push_back(edge(j,w));
            }
        }
        printf("%d\n",heap_prime(G,n));
    }
}

Kruskal:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

struct edge{
    int s,e,w;
    edge(int ss,int ee,int ww):s(ss),e(ee),w(ww){}
    bool operator<(const edge &e1) const{
        return w < e1.w;
    }
};
vector<edge>edges;
vector<int>parent;

int get_root(int a){
    if(parent[a] == a)
        return a;
    parent[a] = get_root(parent[a]);
        return parent[a];
}

void merge(int a,int b){
    int p1 = get_root(a);
    int p2 = get_root(b);
    if(p1 == p2)
        return;
    else{
        parent[p2] = p1;
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        parent.clear();
        edges.clear();
        for(int i = 0;i < n;i++){
            parent.push_back(i);
        }
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                int w;
                scanf("%d",&w);
                edges.push_back(edge(i,j,w));
            }
        }
        sort(edges.begin(),edges.end());
        int done = 0;
        int totalLen = 0;
        for( int i = 0;i < edges.size(); ++i) {
            if( get_root(edges[i].s) != get_root(edges[i].e)) {
                merge(edges[i].s,edges[i].e);
                    ++done;
                    totalLen += edges[i].w;
            }
            if( done == n-1)
                break;
        }
        cout << totalLen << endl;
    }

}

猜你喜欢

转载自blog.csdn.net/qq_42018521/article/details/82025384