最小生成树

SDUTOJ3362 2144
附模板(其实我不懂模板是啥)
#include <bits/stdc++.h>
#define inf 100000000;
using namespace std;

int mp[1010][1010];//存两点之间的长度(距离)
int low[1010];//记录两点之间的最短距离,进行松弛
bool vis[1010];//标记数组,防止走过一个点多次造成死循环

int prim(int n)//n是节点数,这类题目一般都是编号1~n的n个点之间找出最小生成树(其实不加这个参数也行)
{
    int i, j;//循环变量
    int nxt;//记录和上一个点距离最短的点,感觉大部分人喜欢用v,我不管,我就喜欢用nxt,啦啦啦
    int minn;//距离的最小值,min是一个函数没法作为变量名,残念ing
    int sum;//距离之和
    sum = 0;//初始化
    vis[1] = 1;//把第一个点在标记数组里记录一下,表明1这个点已经走过了
    for(i = 1; i <= n; i++)
        low[i] = mp[1][i];//把和第一个点相连的点的路径长度保存在low数组里
    for(i = 2; i <= n; i++)//一共循环n-1,第一个点不用找,可以画个图理解
    {
        minn = inf;//把最小值设置成一个非常大的数,用来进行更新
        nxt = -1;//nxt值设为-1
        for(j = 1; j <= n; j++)
        {
            if(!vis[j] && low[j] < minn)//如果这个点和上一个相邻,没有走过,并且low中记录的当前点的距离要小于记录到的最小值,则if语句成立(说白了这句话就是找一个距离最近的相邻点)
            {
                minn = low[j];//赋值
                nxt = j;//记录点
            }
        }
        if(nxt != -1)//如果等于-1说明没有找到合适的点
        {
            sum += minn;//累加最小值
            vis[nxt] = 1;//把此点标记
        }
        for(j = 1; j <= n; j++)
        {
            if(vis[j] != 1 && mp[nxt][j] < low[j])//进行松弛操作,如果有和nxt相邻的点的距离小于low数组中记录的点,更新low数组
            {
                low[j] = mp[nxt][j];
            }
        }
    }
    for(i = 1; i <= n; i++)//有孤立节点的情况,这里把sum改成-1,根据题目要求改
    {
        if(!vis[i])
        {
            sum = -1;
            break;
        }
    }
    return sum;
}

int main()
{
    int i, j;
    int n, m;
    int u, v, cost;
    int sum;
    while(~scanf("%d %d", &n, &m))
    {
        memset(vis, 0, sizeof(vis));
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
            {
                if(i == j)
                    mp[i][j] = 0;//i=j设为0
                else
                    mp[i][j] = inf;
            }
        for(i = 0; i < m; i++)
        {
            scanf("%d %d %d", &u, &v, &cost);
            mp[u][v] = mp[v][u] = cost;//没有考虑重边情况
        }
        sum = prim(n);
        printf("%d\n", sum);
    }

    return 0;
}
Problem Description
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
Input
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <= 3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。 
Output
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。 
Example Input
5 8
1 2 12
1 3 9
1 4 11
1 5 3
2 3 6
2 4 9
3 4 4
4 5 6
Example Output

19

代码

#include <bits/stdc++.h>
#define inf 100000000;
using namespace std;

int mp[1010][1010];
int low[1010];
bool vis[1010];

int prim(int n)
{
    int i, j;
    int nxt;
    int minn;
    int sum;
    sum = 0;
    vis[1] = 1;
    for(i = 1; i <= n; i++)
        low[i] = mp[1][i];
    for(i = 2; i <= n; i++)
    {
        minn = inf;
        nxt = -1;
        for(j = 1; j <= n; j++)
        {
            if(!vis[j] && low[j] < minn)
            {
                minn = low[j];
                nxt = j;
            }
        }
        if(nxt != -1)
        {
            sum += minn;
            vis[nxt] = 1;
        }
        for(j = 1; j <= n; j++)
        {
            if(vis[j] != 1 && mp[nxt][j] < low[j])
            {
                low[j] = mp[nxt][j];
            }
        }
    }
    for(i = 1; i <= n; i++)
    {
        if(!vis[i])
        {
            sum = -1;
            break;
        }
    }
    return sum;
}

int main()
{
    int i, j;
    int n, m;
    int u, v, cost;
    int sum;
    while(~scanf("%d %d", &n, &m))
    {
        memset(vis, 0, sizeof(vis));
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
            {
                if(i == j)
                    mp[i][j] = 0;
                else
                    mp[i][j] = inf;
            }
        for(i = 0; i < m; i++)
        {
            scanf("%d %d %d", &u, &v, &cost);
            mp[u][v] = mp[v][u] = cost;
        }
        sum = prim(n);
        printf("%d\n", sum);
    }

    return 0;
}

图结构练习——最小生成树

Time Limit: 1000MS  Memory Limit: 65536KB
Problem Description
 有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的。现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市。
 
Input
 输入包含多组数据,格式如下。
第一行包括两个整数n m,代表城市个数和可以修建的公路个数。(n <= 100, m <=10000)
剩下m行每行3个正整数a b c,代表城市a 和城市b之间可以修建一条公路,代价为c。
 
Output
 每组输出占一行,仅输出最小花费。
Example Input
3 2
1 2 1
1 3 1
1 0
Example Output
2
0

//此题有重边情况
#include <bits/stdc++.h>
#define inf 100000000;
using namespace std;

int mp[1010][1010];
int low[1010];
bool vis[1010];

int prim(int n)
{
    int i, j;
    int nxt;
    int minn;
    int sum;
    sum = 0;
    vis[1] = 1;
    for(i = 1; i <= n; i++)
        low[i] = mp[1][i];
    for(i = 2; i <= n; i++)
    {
        minn = inf;
        nxt = -1;
        for(j = 1; j <= n; j++)
        {
            if(!vis[j] && low[j] < minn)
            {
                minn = low[j];
                nxt = j;
            }
        }
        if(nxt != -1)
        {
            sum += minn;
            vis[nxt] = 1;
        }
        for(j = 1; j <= n; j++)
        {
            if(vis[j] != 1 && mp[nxt][j] < low[j])
            {
                low[j] = mp[nxt][j];
            }
        }
    }
    for(i = 1; i <= n; i++)
    {
        if(!vis[i])
        {
            sum = -1;
            break;
        }
    }
    return sum;
}

int main()
{
    int i, j;
    int n, m;
    int u, v, cost;
    int sum;
    while(~scanf("%d %d", &n, &m))
    {
        memset(vis, 0, sizeof(vis));
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
            {
                if(i == j)
                    mp[i][j] = 0;
                else
                    mp[i][j] = inf;
            }
        for(i = 0; i < m; i++)
        {
            scanf("%d %d %d", &u, &v, &cost);
            if(cost < mp[u][v])//在此判断
            mp[u][v] = mp[v][u] = cost;
        }
        sum = prim(n);
        printf("%d\n", sum);
    }

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值