06-图6. 公路村村通(30)--最小生成树-prime-kruskal

08-图7 公路村村通 (30分)
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
输出样例:
12

题目地址:http://pta.patest.cn/pta/test/18/exam/4/question/630

prime
prime算法可以随意选择一个起始点,并且为每个节点维持一个到起点的最短的路径长度,不断的更新加入到生成树种,直到所有节点都加入到树中。

#include <cstdio>
#include <iostream>  
#include <vector>  
#include <map>  
#include <set>  
#include <string>  
#include <cstring>
#include <algorithm>  
#include <sstream>
#include <iterator>
#include <queue>
#include <stack>
#include <functional>

using namespace std ;

#define N 1002
#define INF 1 << 30 

int n , m ;

struct edge{
    int v ;
    int dist ;
};

vector<edge> ve[N] ;

bool vis[N] ;
int low[N] ;

int prime()
{
    int i ;
    for(i = 1 ; i <= n ; i++)
    {
        vis[i] = false ;
        low[i] = INF ;
    }
    low[1] = 0 ;
    int num = 0 ;
    int sum = 0 ;
    while(num != n)
    {
        int minn = INF ;
        int nextP = -1 ;// 下一个节点
        for(i = 1 ; i <= n ; i++)//遍历所有的节点,找到最小的low[i]
        {
            if(!vis[i] && low[i] < minn)
            {
                minn = low[i] ;
                nextP = i ;
            }
        } // for
        if(nextP == -1)
            return -1 ;

        sum += minn ;
        vis[nextP] = true ;

        int len = ve[nextP].size() ;
        for(i = 0 ;i < len ; i++) // 调整low[i]
        {
            int v = ve[nextP][i].v ;
            int dist = ve[nextP][i].dist ;
            if(!vis[v] && dist < low[v] )
            {
                low[v] = dist ;
            }
        }
        num ++ ;

    }// while   
    if(num != n )
        return -1 ;
    return sum ;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    scanf("%d%d",&n,&m) ;
    int i ;
    int u , v , dist ;
    edge et ;
    for(i = 0 ;i < m ; i++)
    {
        scanf("%d%d%d" ,&u , &v , &dist) ;
        et.v = v ;
        et.dist = dist;
        ve[u].push_back(et) ;
        et.v = u ;
        ve[v].push_back(et);
    }
    printf("%d\n" , prime() ) ;
    return 0;
}

prime解法

#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <vector>
#include <string>
#include <iostream>
#include <cmath>
#include <queue>
using namespace std;

#define N 1002
#define INF 999999999

int n,m;

int mp[N][N];

int low[N];
int vis[N];

int prime()
{
    int costs = 0;
    int i, j;
    int newP = 1;
    for (i = 1; i <= n; i++)
    {
        low[i] = mp[newP][i];
        vis[i] = false;
    }
    vis[newP] = true;
    int num = 1;

    while (num < n)
    {
        int minn = INF;
        int tmpNewP = newP;
        for (i = 1; i <= n; i++)
        {
            if (!vis[i] && low[i] < minn)
            {
                minn = low[i];
                newP = i;
            }
        }
        if (minn == INF) // 找不到这样的一点
        {
            return -1;
        }
        num++;
        //costs += mp[tmpNewP][newP];
        costs += low[newP]; // 这里是加上low[newP] 否则错误 , 是最小
        for (i = 1; i <= n; i++)
        {
            if (!vis[i] && mp[newP][i] < low[i])
            {
                low[i] = mp[newP][i];
            }
        }
        vis[newP] = true;
    }
    if (num < n)
        return -1;
    return costs;
}

int main()
{
    //freopen("in", "r", stdin);  
    int i, j;
    while (scanf("%d%d",&n,&m) != EOF)
    {
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= n; j++)
            {
                mp[i][j] = INF;
                mp[j][i] = INF;
            }
            mp[i][i] = 0;
        }
        int u, v, cost;
        for (i = 0; i < m; i++)
        {
            scanf("%d%d%d", &u, &v, &cost);
            mp[u][v] = cost;
            mp[v][u] = cost;
        }
        printf("%d\n", prime());
    }
    //printf("\n");
    return 0;
}

kruskal+并查集

#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <vector>
#include <string>
#include <iostream>
#include <cmath>
#include <queue>
using namespace std;

#define N 1002
int n,m;

struct edge{
  int u, v, cost;
};

vector<edge> ve;

bool cmp(edge e1, edge e2)
{
  return e1.cost < e2.cost;
}

int father[N];

int find(int x)
{
  if (x == father[x])
    return x;
  return father[x] = find(father[x]);
}

void merge(int x, int y)
{
  father[find(y)] = find(x);
}

int kruskal()
{
  int costs = 0;
  int num = 0;
  int coutNow = 0;
  // n - 1条边可以加入就行了
  while (num < n-1)
  {
    if (coutNow >= m)
    {
      break;
    }
    edge etNow = ve[coutNow++];
    int u = etNow.u;
    int v = etNow.v;
    if (find(u) != find(v))
    {
      merge(u, v);
      num++;
      costs += etNow.cost;
    }
  }
  if (num != n - 1)
    return -1;
  return costs;
}

int main()
{
  //freopen("in", "r", stdin);  
  int i, j;
  while (scanf("%d%d",&n,&m) != EOF)
  {
    edge et;
    ve.clear();
    for (i = 1; i <= n; i++)
    {
      father[i] = i;
    }
    for (i = 0; i < m; i++)
    {
      scanf("%d%d%d", &et.u, &et.v, &et.cost);
      ve.push_back(et);
    }
    sort(ve.begin(), ve.end(), cmp);

    printf("%d\n",kruskal());
  }
  //printf("\n");
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值