自来水管道

问题 R: 自来水管道
时间限制: 1 Sec 内存限制: 128 MB
提交: 840 解决: 241
[提交][状态][讨论版]
题目描述

你领到了一个铺设校园内自来水管道的任务。校园内有若干需要供水的点,每两个供水点可能存在多种铺设路径。对于每一种铺设路径,其成本是预知的。
任务要求最终铺设的管道保证任意两点可以直接或间接的联通,同时总成本最低。

输入
每个测试用例由多行组成,第一行是两个整数P和R,P代表供水点数(1<=P<=50),每个点都对应1到P中的一个唯一编号。R代表可能的铺设路径数,路径数可能有非常多。接下有R行,每行格式如下:
节点A编号 节点B编号 路径成本
路径成本不超过100。
测试用例之间有一空行分开。输入结束用P=0表示,注意没有R值。
输出
每个测试用例占用一行输出最低总成本。
样例输入
1 0

2 3
1 2 37
2 1 17
1 2 68

3 7
1 2 19
2 3 11
3 1 7
1 3 5
2 3 89
3 1 91
1 2 32

5 7
1 2 5
2 3 7
2 4 8
4 5 11
3 5 10
1 5 6
4 2 12

0
样例输出
0
17
16
26

分析:典型的prim算法,求最小生成树,把邻接矩阵构造好,就OK了。

#include<stdio.h>
#define max 1e7
#define MAXCOST 1e7
#define MAX 100
int Prim(int graph[MAX][MAX],long long int n)
{
 /* lowcost[i]记录以i为终点的边的最小权值,当lowcost[i]=0时表示终点i加入生成树 */
 int lowcost[MAX];
 
 /* mst[i]记录对应lowcost[i]的起点 */
 int mst[MAX];
 
 int i, j, min, minid, sum = 0;
 
 /* 默认选择0号节点加入生成树,从1号节点开始初始化 */
 for (i = 1; i < n; i++)
 {
  /* 最短距离初始化为其他节点到0号节点的距离 */
   lowcost[i] = graph[0][i];
 
  /* 标记所有节点的起点皆为默认的0号节点 */
  mst[i] = 0;
 }
 
 /* 标记0号节点加入生成树 */
 lowcost[0] = 0;
 
 /* n个节点至少需要n-1条边构成最小生成树 */
 for (i = 1; i < n; i++)
 {
  min = MAXCOST;
  minid = 0;
 
  /* 找满足条件的最小权值边的节点minid */
  for (j =1; j <n; j++)
  {
   /* 边权值较小且不在生成树中 */
   if (lowcost[j] < min && lowcost[j] != 0)
   {
    min = lowcost[j];
    minid = j;
   }
  }
  /* 输出生成树边的信息:起点,终点,权值 */
  //cout<<"生成数边的起点、终点及权值分别为:"<< mst[minid]+1<<"  "<<minid+1<<"  "<<min<<endl;
  /* 累加权值 */
  sum += min;
 
  /* 标记节点minid加入生成树 */
  lowcost[minid] = 0;
 
  /* 更新当前节点minid到其他节点的权值 */
  for (j = 1; j < n; j++)
  {
   /* 发现更小的权值 */
   if (graph[minid][j] < lowcost[j])
   {
    /* 更新权值信息 */
    lowcost[j] = graph[minid][j];
 
    /* 更新最小权值边的起点 */
    mst[j] = minid;
   }
  }
 }
 /* 返回最小权值和 */
 return sum;
}
 
 
int a[100][100];
int b[1000000][4];//存题目输入数据
int main()
{
    int P,R,i,j,k;
    while(~scanf("%d",&P)&&P!=0&&~scanf("%d",&R))
    {
        for(i=0;i<R;i++)
            for(j=0;j<3;j++)
            scanf("%d",&b[i][j]);
        for(i=0;i<P;i++)
            a[i][i]=0;//自身结点权值为0
        for(i=0;i<P;i++)
            for(j=0;j<P;j++)
            if(i!=j)
            {a[i][j]=max;a[j][i]=max;}//初始化为无穷大
        for(k=0;k<R;k++)
        {
            i=b[k][0]-1;
            j=b[k][1]-1;
            if(a[i][j]==max)
                {a[i][j]=b[k][2];a[j][i]=b[k][2];}//邻接矩阵
            else
                if(b[k][2]<a[i][j])
                    {a[i][j]=b[k][2];a[j][i]=b[k][2];}//筛选两节点之间最小成本。
        }
        printf("%d\n",Prim(a,P));
 
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛歌依旧fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值