图论问题(2) : hdu 1102

题目转自hdu 1102,题目传送门

题目大意:

输入一个n*n的邻接矩阵,其中i行j列代表从i到j的路径的长度

然后又m条路已经帮你修好了,求最短要修多长的路才能使所有村庄连接

不难看出,这道题就是标准的最小生成树模板,多水啊

虽然很水,但本人还是调了近1h才把代码调好......

下面介绍一下解决最小生成树的两个方法:

Prim 和 Kruskal

一,Prim(不懂的点这里)

Prim的思想和dijkstra的想法很想(如果不知道dijkstra算法的请点这里)

那么Prim的复杂度在为优化之前是O(n2),还是很慢的(虽然这道题能过)

既然这样,那这道题该怎么用Prim解呢?

思考了近10min后我想到了一个绝妙的方法,但是这里地方太小写不下

既然已经有建好了的,那我们肯定要用他已经建好的

所以,我们在输入时做一个预处理

将所有已经建过的路的距离化为0,然后再跑一遍Prim就行了

预处理代码如下:

for(int i=1;i<=m;i++)
{
    int x,y;
    scanf("%d%d",&x,&y);
    g[x][y]=g[y][x]=0;
}

p.s.:g为邻接矩阵

然后在花15min打一遍Prim算法就可以愉快地AC了

AC代码如下:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define inf 2147483647
using namespace std;
bool vis[105];
int n,m,cnt,ans,u;
int dis[105];
int g[105][105];
void init()
{
    ans=cnt=0;
    memset(vis,false,sizeof(vis));
    memset(dis,0x7f,sizeof(dis));
    return ;
}
void pirm()
{
    dis[1]=0;
    while(true)
    {
        u=0;
        for(int i=1;i<=n;i++)
            if(!vis[i] && (dis[i]<dis[u])) u=i;
        if(u==0) return ;
        vis[u]=true;
        ans+=dis[u];
        for(int i=1;i<=n;i++) dis[i]=min(dis[i],g[u][i]);
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&g[i][j]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            g[x][y]=g[y][x]=0;
        }
        pirm();
        printf("%d\n",ans);
    }
    return 0;
}

接下来看Kruskal......

二,Kruskal(不懂的点这里)

Kruskal中将用到hdu 1198中的并查集(点此转到我的的博客:图论问题(1):hdu 1198

Kruskal主要就是把边按边权从小到大排序

在通过并查集检查目前最小的边的两端是否在同一集合中

若是,则跳过这条边

否则就把他们归为一个集合

这里只需要提前作这一步骤就行了

预处理代码如下:

for(int i=1;i<=m;i++)
{
    int x,y;
    scanf("%d%d",&x,&y);
    Union(x,y);
}

p.s.:其中Union为合并函数

然后就花个20min写完模板就可以愉快地AC了

AC代码如下:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct edge
{
    int from,to,w;
    bool operator<(const edge &a)const
    {
        return w<a.w;
    }
}e[10005];
int n,m,cnt,ans;
int fa[105];
void init()
{
    for(int i=1;i<=n;i++) fa[i]=i;
    cnt=ans=0;
    return ;
}
int find_fa(int x)
{
    if(x==fa[x]) return x;
    else
    {
        fa[x]=find_fa(fa[x]);
        return fa[x];
    }
    return 0;
}
void Union(int x,int y)
{
    x=find_fa(x);
    y=find_fa(y);
    if(x<y) fa[y]=x;
    else fa[x]=y;
    return ;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&e[cnt].w);
                e[cnt].from=i;e[cnt].to=j;
                cnt++;
            }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            Union(x,y);
        }
        sort(e,e+cnt);
        for(int i=0;i<cnt;i++)
            if(find_fa(e[i].from)!=find_fa(e[i].to))
            {
                Union(e[i].from,e[i].to);
                ans+=e[i].w;
            }
        printf("%d\n",ans);
    }
    return 0;
}

今天的讲解就到这了,若果有没有听懂的可以借鉴一下《啊哈!算法》

或者期待一下,本人即将开始的专辑 “算法详讲” 和 “STL应用”(广告乱入)

期待一下哈!

原文地址:https://www.cnblogs.com/juruo-hxy/p/12000086.html

时间: 2024-07-28 13:06:56

图论问题(2) : hdu 1102的相关文章

HDU 1102 最小生成树裸题,kruskal,prim

1.HDU  1102  Constructing Roads    最小生成树 2.总结: 题意:修路,裸题 (1)kruskal //kruskal #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using na

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 conne

HDU 1102 Kruscal算法

题目大意:给定村庄的数量,和一个矩阵表示每个村庄到对应村庄的距离,矩阵主对角线上均为1 在给定一个数目Q,输入Q行之间已经有通道的a,b 计算还要至少修建多少长度的轨道 这道题目用Kruscal方法进行计算,先将已有路径记为0,再进行所有路径长度的排序(只计算一个下三角或一个上三角,还把主对角线去掉的那种),通过并查集相交的方法,来判断二者是否属于同一个连通分量,由小到大不断找到你选取的路径,将其加起来即可 代码如下: 1 #include <iostream> 2 #include<c

HDU 1102 &amp;&amp; POJ 2421 Constructing Roads (经典MST~Prim)

链接:http://poj.org/problem?id=2421  或   http://acm.hdu.edu.cn/showproblem.php?pid=1102 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

HDU 1102 Constructing Roads (裸的并查集)

Constructing Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13210    Accepted Submission(s): 4995 Problem Description There are N villages, which are numbered from 1 to N, and you should

hdu 1102 Constructing Roads Kruscal

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 题意:这道题实际上和hdu 1242 Rescue 非常相似,改变了输入方式之后, 本题实际上更适合用Prim来做. 用Kruscal的话要做一些变化. /*Constructing Roads Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s)

hdu 1102 Constructing Roads (Prim算法)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 Constructing Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21947    Accepted Submission(s): 8448 Problem Description There are N villa

hdu 1102 Constructing Roads(最小生成树 Prim)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 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 conne

HDU 1102 Constructing Roads【简单最小生成树,Prime算法+Kruskal算法】

Constructing Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 20765    Accepted Submission(s): 7934 Problem Description There are N villages, which are numbered from 1 to N, and you should