问题 O: 自来水管道

前言必读!http://blog.csdn.net/hnust_v/article/details/51747743
问题 O: 自来水管道
时间限制: 1 Sec 内存限制: 128 MB
提交: 190 解决: 64
[提交][状态][讨论版]
题目描述

你领到了一个铺设校园内自来水管道的任务。校园内有若干需要供水的点,每两个供水点可能存在多种铺设路径。对于每一种铺设路径,其成本是预知的。

    任务要求最终铺设的管道保证任意两点可以直接或间接的联通,同时总成本最低。
输入

每个测试用例由多行组成,第一行是两个整数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水题,没什么好说的
给出Prim伪代码

1).输入:一个加权连通图,其中顶点集合为V,边集合为E2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
C++:实现
#include <bits/stdc++.h>
using namespace std;
#define INF -1
#define MAXN 100
#define Protect 2
int Point[Protect*MAXN][Protect*MAXN];  //A->B 值为Cost
int MinE[Protect*MAXN];                 //当前到点 i 最短路
bool Visit[Protect*MAXN];               //Prim  是否访问过
bool Judge[Protect*MAXN][Protect*MAXN]; //Handle是否已经有边
void Print_Mat(int n)
{
    printf("The Mat_________________________________\n\n\n");
    for(int i=1;i<=n;i++,printf("\n\n"))
        for(int j=1;j<=n;j++) printf("%4d ",Point[i][j]);
    printf("\n\nEND_____________________________________\n\n\n");
}
void Handle(int V,int E)
{//V个顶点,E条边
    memset(Point,-1,sizeof(Point));
    memset(Judge,false,sizeof(Judge));
    for(int i=1,A,B,Cost;i<=E;i++)
    {
        scanf("%d %d %d",&A,&B,&Cost);
        {
            if(Judge[A][B]) Point[A][B] = min(Point[A][B],Cost);
            else {Judge[A][B] = !Judge[A][B]; Point[A][B] = Cost; }
            if(Judge[B][A]) Point[B][A] = min(Point[B][A],Cost);
            else {Judge[B][A] = !Judge[B][A]; Point[B][A] = Cost; }
        }//读取并保证最小边
    }
}
int Search(int now,int & Cost,int n)
{//当前点,当前耗费,总点数
    int next,Min_next=INT_MAX;
    for(int i=1;i<=n;i++)
    {
         if(Visit[i])   continue;        //该点已在集合内
         MinE[i] = MinE[i]!=INF&&Point[now][i]!=INF? min(MinE[i],Point[now][i]):max(MinE[i],Point[now][i]);
         //更新最小点集距离
         if(MinE[i]!=INF && Min_next > MinE[i])
         {
             Min_next = MinE[i];
             next = i;
         }
    }
    Visit[next]=true;MinE[next]=0;
    Cost += Min_next+1>0?Min_next:0;
    return next;
}//返回下一个最小的邻接点
int Prim(int n)
{
    memset(MinE,INF,sizeof MinE);//当前到点i最短路,设定全不联通
    memset(Visit,0,sizeof Visit);//标记为都未访问
    int Cost = 0,Count = 1;//Cost 最小耗费,Count已经有的点,默认点1已经在内
    Visit[1]=true;//从点1开始访问
    int next;
    if(n > 1) next = Search(1,Cost,n);  //防止只有1个点
    while(++Count < n)
       next = Search(next,Cost,n);
    return Cost;
}

int main(void)
{
    //freopen("F:\\test.txt","r",stdin);
    int V,E;
    while(cin>>V&&V)
    {
        cin>>E;
        Handle(V,E);//Print_Mat(V);
        printf("%d\n",Prim(V));
    }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值