poj 1258 Agri-Net

来源:互联网 发布:蔡幸娟 星星知我心 编辑:程序博客网 时间:2024/05/19 13:58

poj 1258 Agri-Net


Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 51094 Accepted: 21275

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

最小生成树——Prim算法

// N个顶点int N;struct Vertex {    // 顶点编号    int v;    // 到该顶点的权值    int w;    Vertex(int vv, int ww): v(vv),w(ww) {};    bool operator < (const Vertex& v1) const{        return w > v1.w;    }};// 邻接表vector<vector<Vertex> > G(MAX_VERTEX);// prim算法,最小生成树点构造性算法// 图,节点数和开始访问节点int prim(const vector<vector<Vertex> > &G, int n, int u) {    // 优先队列    priority_queue<Vertex> pq;    pq.push(G[u][u]);    // 访问表    vector<int> visited(n);    // 各顶点到已建好那部分树的距离    vector<int> dist(n);    // 被加入访问表结点的数目    int visNum = 0;    // 总权值    int totalW = 0;    // 初始化各顶点为未访问,距离为无穷大    for(int i = 0; i < n; i++) {        visited[i] = 0;        dist[i] = INF;    }    // 结点未被遍历完并且队列不为空    while(visNum < N && !pq.empty()) {        Vertex v = pq.top();        pq.pop();        // 已在访问表的结点不需要更新        if(visited[v.v]) {            continue;        }        // 数据更新        totalW += v.w;        visited[v.v] = 1;        visNum++;        // 更新新加入的邻边        for(int i = 0; i < G[v.v].size(); i++) {            int k = G[v.v][i].v;            int w = G[v.v][i].w;            // k未被访问过并且到k的距离小于k到已使用点集的距离            if(!visited[k] && w < dist[k]) {                dist[k] = w;                pq.push(Vertex(k, w));            }        }    }    // 图不连通    if(visNum < n) {        return -1;    }    return totalW;}

源代码

#include <cstdio>#include <vector>#include <cstring>#include <queue>using namespace std;const int INF = 1 << 30;const int MAX_VERTEX = 100 + 10;// N个顶点int N;struct Vertex {    // 顶点编号    int v;    // 到该顶点的权值    int w;    Vertex(int vv, int ww): v(vv),w(ww) {};    bool operator < (const Vertex& v1) const{        return w > v1.w;    }};// 邻接表vector<vector<Vertex> > G(MAX_VERTEX);// prim算法,最小生成树点构造性算法// 图,节点数和开始访问节点int prim(const vector<vector<Vertex> > &G, int n, int u) {    // 优先队列    priority_queue<Vertex> pq;    pq.push(G[u][u]);    // 访问表    vector<int> visited(n);    // 各顶点到已建好那部分树的距离    vector<int> dist(n);    // 被加入访问表结点的数目    int visNum = 0;    // 总权值    int totalW = 0;    // 初始化各顶点为未访问,距离为无穷大    for(int i = 0; i < n; i++) {        visited[i] = 0;        dist[i] = INF;    }    // 结点未被遍历完并且队列不为空    while(visNum < N && !pq.empty()) {        Vertex v = pq.top();        pq.pop();        // 已在访问表的结点不需要更新        if(visited[v.v]) {            continue;        }        // 数据更新        totalW += v.w;        visited[v.v] = 1;        visNum++;        // 更新新加入的邻边        for(int i = 0; i < G[v.v].size(); i++) {            int k = G[v.v][i].v;            int w = G[v.v][i].w;            // k未被访问过并且到k的距离小于k到已使用点集的距离            if(!visited[k] && w < dist[k]) {                dist[k] = w;                pq.push(Vertex(k, w));            }        }    }    // 图不连通    if(visNum < n) {        return -1;    }    return totalW;}int main() {    while(scanf("%d", &N) != EOF) {        // 清除数据        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);                Vertex v(j, w);                G[i].push_back(v);            }        }        printf("%d\n", prim(G, N, 0));    }    return 0;}

最小生成树Kruscal算法

const int INF = 1 << 30;const int MAX_VERTEX = 100 + 10;// N个顶点int N;struct EDGE {    // 起始点    int s;    // 终止点    int e;    // 权值    int w;    EDGE(int ss, int ee, int ww):s(ss),e(ee),w(ww) {};    bool operator < (const EDGE& e) const{        return w > e.w;    }};priority_queue<EDGE> edges;// 并查集vector<int> parent(MAX_VERTEX);// 初始化void init(int N) {    for(int i = 0; i < N; i++) {        parent[i] = i;    }}// 找到根节点int findSet(int p) {    if(p == parent[p]) {        return p;    } else {        return parent[p] = findSet(parent[p]);    }}// s,e是否在一个集合bool isSomeSet(int s, int e) {    return findSet(s) == findSet(e);}// 合并s,e的集合void unite(int s, int e) {    int rootS = findSet(s);    int rootE = findSet(e);    if(rootS == rootE) {        return;    }    parent[rootE] = rootS;}// kruscal算法,最小生成树边构造性算法// 节点数int kruscal(int N) {    // 使用并查集    init(N);    // 被加入的总边数    int visEdgeNum = 0;    // 总权值    int totalW = 0;    // 结点未被访问完且还有边没访问    while(visEdgeNum < N - 1 && !edges.empty()) {        EDGE edge = edges.top();        edges.pop();        // 构成环        if(isSomeSet(edge.s, edge.e)) {            continue;        }        // 数据更新        visEdgeNum++;        totalW += edge.w;        // 将点s,点e放入一个集合中        unite(edge.s, edge.e);    }    // 该图不是连通图    if(visEdgeNum != N - 1) {        return -1;    }    return totalW;}

源代码

#include <cstdio>#include <queue>#include <vector>using namespace std;const int INF = 1 << 30;const int MAX_VERTEX = 100 + 10;// N个顶点int N;struct EDGE {    // 起始点    int s;    // 终止点    int e;    // 权值    int w;    EDGE(int ss, int ee, int ww):s(ss),e(ee),w(ww) {};    bool operator < (const EDGE& e) const{        return w > e.w;    }};priority_queue<EDGE> edges;// 并查集vector<int> parent(MAX_VERTEX);// 初始化void init(int N) {    for(int i = 0; i < N; i++) {        parent[i] = i;    }}// 找到根节点int findSet(int p) {    if(p == parent[p]) {        return p;    } else {        return parent[p] = findSet(parent[p]);    }}// s,e是否在一个集合bool isSomeSet(int s, int e) {    return findSet(s) == findSet(e);}// 合并s,e的集合void unite(int s, int e) {    int rootS = findSet(s);    int rootE = findSet(e);    if(rootS == rootE) {        return;    }    parent[rootE] = rootS;}// kruscal算法,最小生成树边构造性算法// 节点数int kruscal(int N) {    // 使用并查集    init(N);    // 被加入的总边数    int visEdgeNum = 0;    // 总权值    int totalW = 0;    // 结点未被访问完且还有边没访问    while(visEdgeNum < N - 1 && !edges.empty()) {        EDGE edge = edges.top();        edges.pop();        // 构成环        if(isSomeSet(edge.s, edge.e)) {            continue;        }        // 数据更新        visEdgeNum++;        totalW += edge.w;        // 将点s,点e放入一个集合中        unite(edge.s, edge.e);    }    // 该图不是连通图    if(visEdgeNum != N - 1) {        return -1;    }    return totalW;}int main() {    while(scanf("%d", &N) != EOF) {        // 清楚数据        while(!edges.empty()) {            edges.pop();        }        // 邻接矩阵转化为邻接表        for(int i = 0; i < N; i++) {            for(int j = 0; j < N; j++) {                int w;                scanf("%d", &w);                if(w != 0) {                    edges.push(EDGE(i, j, w));                }            }        }        printf("%d\n", kruscal(N));    }    return 0;}
0 0
原创粉丝点击