HDU 1102 Constructing Roads, Prim+優先隊列

題目鏈接:HDU 1102 Constructing Roads

Constructing Roads



Problem Description
There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected. 

We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.
 

Input
The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j.

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.
 

Output
You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum. 
 

Sample Input
3 0 990 692 990 0 179 692 179 0 1 1 2
 

Sample Output
179
 

Source
 

Recommend
Eddy   |   We have carefully selected several similar problems for you:  1142 1598 1116 1269 1596 
 
題意

有N個村子要修道路,給出了修每條道路的原始費用,現在有的道路已經修好了。我們要求的是修剩下的道路的最小費用。

分析

最小生成樹算法,因爲是鄰接矩陣,因而使用Prim方法非常方便求解,對於已經修好的道路,我們可以將他們的費用設置爲0,再用Prim算法求解即可得到。

代碼

鄰接矩陣:
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

#define maxn 110
#define INF 0xffff
int g[maxn][maxn];
int n;

struct node
{
    int v, key;
    friend bool operator<(node a, node b)
    {
        return a.key > b.key;
    }
};

bool visited[maxn];
node vx[maxn];
priority_queue<node> q;
void Prim()
{
    for(int i = 1; i <= n; i++)
    {
        vx[i].v = i;
        vx[i].key = INF;
        visited[i] = false;
    }
    vx[1].key = 0;
    q.push(vx[1]);
    while(!q.empty())
    {
        node nd = q.top();
        q.pop();
        int st = nd.v;
        if(visited[st])
            continue;
        visited[st] = true;
        for(int j = 1; j <= n; j++)
        {
            if(j != st && !visited[j] && vx[j].key > g[st][j])
            {
                vx[j].key = g[st][j];
                q.push(vx[j]);
            }
        }
    }
}
int main()
{
    int m, a, b;
    while(~scanf("%d", &n))
    {
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
                scanf("%d", &g[i][j]);
            g[i][i] = INF;
        }
        scanf("%d", &m);
        while(m--)
        {
            scanf("%d%d", &a, &b);
            g[a][b] = g[b][a] = 0;
        }
        Prim();
        int ans = 0;
        for(int i = 1; i <= n; i++)
            ans += vx[i].key;
        printf("%d\n", ans);

    }
    return 0;
}

鄰接表:
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;

#define maxn 110  //最大頂點個數
int n, m;       //頂點數,邊數

struct arcnode  //邊結點
{
    int vertex;     //與表頭結點相鄰的頂點編號
    int weight;     //連接兩頂點的邊的權值
    arcnode * next; //指向下一相鄰接點
    arcnode() {}
    arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
};

struct vernode      //頂點結點,爲每一條鄰接表的表頭結點
{
    int vex;    //當前定點編號
    arcnode * firarc;   //與該頂點相連的第一個頂點組成的邊
}Ver[maxn];

void Init()  //建立圖的鄰接表需要先初始化,建立頂點結點
{
    for(int i = 1; i <= n; i++)
    {
        Ver[i].vex = i;
        Ver[i].firarc = NULL;
    }
}
void Insert(int a, int b, int w)  //尾插法,插入以a爲起點,b爲終點,權爲w的邊,效率不如頭插,但是可以去重邊
{
    arcnode * q = new arcnode(b, w);
    if(Ver[a].firarc == NULL)
        Ver[a].firarc = q;
    else
    {
        arcnode * p = Ver[a].firarc;
        if(p->vertex == b)
        {
            if(p->weight > w)
                p->weight = w;
            return ;
        }
        while(p->next != NULL)
        {
            if(p->next->vertex == b)
            {
                if(p->next->weight > w);
                    p->next->weight = w;
                return ;
            }
            p = p->next;
        }
        p->next = q;
    }
}
void Insert2(int a, int b, int w)   //頭插法,效率更高,但不能去重邊
{
    arcnode * q = new arcnode(b, w);
    if(Ver[a].firarc == NULL)
        Ver[a].firarc = q;
    else
    {
        arcnode * p = Ver[a].firarc;
        q->next = p;
        Ver[a].firarc = q;
    }
}
struct node     //保存key值的結點
{
    int v;
    int key;
    friend bool operator<(node a, node b)   //自定義優先級,key小的優先
    {
        return a.key > b.key;
    }
};

#define INF 0xfffff    //權值上限
bool visited[maxn]; //是否已經加入樹
node vx[maxn];      //保存每個結點與其父節點連接邊的權值
priority_queue<node> q; //優先隊列stl實現
void Prim()    //s表示根結點
{
    for(int i = 1; i <= n; i++) //初始化
    {
        vx[i].v = i;
        vx[i].key = INF;
        visited[i] = false;
    }
    vx[1].key = 0;
    q.push(vx[1]);
    while(!q.empty())
    {
        node nd = q.top();  //取隊首,記得趕緊pop掉
        q.pop();
        if(visited[nd.v])   //注意這一句的深意,避免很多不必要的操作
            continue;
        visited[nd.v] = true;
        arcnode * p = Ver[nd.v].firarc;
        while(p != NULL)    //找到所有相鄰結點,若未訪問,則入隊列
        {
            if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
            {
                vx[p->vertex].key = p->weight;
                vx[p->vertex].v = p->vertex;
                q.push(vx[p->vertex]);
            }
            p = p->next;
        }
    }
}

int main()
{
    int m, a, b, x;
    while(~scanf("%d", &n))
    {
        Init();
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                scanf("%d", &x);
                if(x != 0)
                    Insert2(i, j, x);
            }
        }
        scanf("%d", &m);
        while(m--)
        {
            scanf("%d%d", &a, &b);
            Insert(a, b, 0);
            Insert(b, a, 0);
        }
        Prim();
        int ans = 0;
        for(int i = 1; i <= n; i++)
            ans += vx[i].key;
        printf("%d\n", ans);

    }
    return 0;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章