码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 1102 Constructing Roads, Prim+优先队列

时间:2014-07-30 12:14:23      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:prim   acm   hdu   图论   

题目链接: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;
}





HDU 1102 Constructing Roads, Prim+优先队列,布布扣,bubuko.com

HDU 1102 Constructing Roads, Prim+优先队列

标签:prim   acm   hdu   图论   

原文地址:http://blog.csdn.net/u011439796/article/details/38295969

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!