P2330 [SCOI2005]繁忙的都市 题解

题目传送门

题目思路

把交叉路口看做图中的点,道路为边,根据以下三个条件:

  1. 改造的那些道路能够把所有的交叉路口直接或间接的连通起来。

  1. 在满足要求1的情况下,改造的道路尽量少。

  1. 在满足要求1、2的情况下,改造的那些道路中分值最大的道路分值尽量小。

由1.可知这个图是连通图;

由2.可知要连n-1条边;

由3.可知连的边的边权和要最小。

所以此题的考点为最小生成树

Prim

最小生成树的实现有两个算法——Prim和Kruskal,这里我们只介绍Prim算法

  1. 想法

Prim的想法是:每次寻找离MST集体最近的点,将点与链接集体的边加入MST

  1. 实现步骤
  1. 任取一个点

  1. 找不在MST中的离MST最近的点K

  1. 将K加入MST

  1. 更新其它点到MST的距离

  1. 重复直到所有点加入MST

  1. 程序实现

Prim的程序实现方法如下:

//dis表示点到MST的最短距离
//vis表示此点在不在MST里 
//G为邻接表
//v为连接的点,w为边权 
int prim()
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0;
    int maxx=0;//分值最大的那条路的分值
    for(int i=1;i<=n;i++)//每一轮在MST里加一个点
    {
        int k=0;//k用来寻找不在MST的离MST最近的点
        for(int j=1;j<=n;j++)//枚举每个点 
            if(!vis[j] && dis[j]<dis[k])//如果这个点不在MST内且比目前最近的点还近就替换成这个点 
                k=j;
        if(k==0) break;//等于零证明完成或图不连通,退出 
        vis[k]=1;//将这个点加入MST 
        maxx=max(maxx,dis[k]);//更新分值最大的那条道路的分值
        for(int j=0;j<G[k].size();j++)//更新其它点到MST的距离
        {
            int v=G[k][j].v,w=G[k][j].w;//提取连接的点和边权 
            if(!vis[v] && w<dis[v]) dis[v]=w;//如果它不在MST内且更近就更新 
        }
    }
    return maxx;
}

Code

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int N=10005; 
struct Node
{
    int v,w;//v为连接的点,w为边权 
};
vector<Node> G[N];//G为邻接表
int dis[N],vis[N];//vis表示此点在不在MST里,dis表示点到MST的最短距离 
int n,m,x,y,z;
int prim()
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0;
    int maxx=0;//分值最大的那条路的分值
    for(int i=1;i<=n;i++)//每一轮在MST里加一个点
    {
        int k=0;//k用来寻找不在MST的离MST最近的点
        for(int j=1;j<=n;j++)//枚举每个点 
            if(!vis[j] && dis[j]<dis[k])//如果这个点不在MST内且比目前最近的点还近就替换成这个点 
                k=j;
        if(k==0) break;//等于零证明完成或图不连通,退出 
        vis[k]=1;//将这个点加入MST 
        maxx=max(maxx,dis[k]);//更新分值最大的那条道路的分值
        for(int j=0;j<G[k].size();j++)//更新其它点到MST的距离
        {
            int v=G[k][j].v,w=G[k][j].w;//提取连接的点和边权 
            if(!vis[v] && w<dis[v]) dis[v]=w;//如果它不在MST内且更近就更新 
        }
    }
    return maxx;
}
int main()
{
    cin>>n>>m;//读入数据 
    while(m--)
    {
        cin>>x>>y>>z;//读入数据 
        G[x].push_back(Node{y,z});//加入新点和边权 
        G[y].push_back(Node{x,z});//因为是无向图,还要反着加一遍 
    }
    cout<<n-1<<" "<<prim();//输出答案 
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值