PTA习题 畅通工程之局部最小花费问题 (并查集)

7-50 畅通工程之局部最小花费问题(35 分)

某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建快速路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全地区畅通需要的最低成本。

输入格式:

输入的第一行给出村庄数目N (1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态 — 1表示已建,0表示未建。

输出格式:

输出全省畅通需要的最低成本。

输入样例:

4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0

输出样例:

3

 

        思路:道路分为两种,一种是已经建立好了的,一种是没有建立的。采用克鲁斯卡尔算法,分为两遍处理,第一遍先把建立好的道路添加图中,只添加会影响连通性的,顺便统计添加了多少条。第二遍再跑一遍克鲁斯卡尔,将没有建好的道路按费用从小到大添加到图中。当添加了n-1条道路时,停止。

        实质上是将克鲁斯卡尔分两遍跑。第一遍跑建好的道路,第二遍跑没建好的道路。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <sstream>
#include <map>
#include <queue>
#include <stack>
#include <cstring>
#include <set>
#include <cmath>
#define INF 1000000

using namespace std;
int n;
struct edge
{
    int x,y,cost,flag;
};
typedef struct edge edge;
edge a[5005];
int m;

int cmp(edge aa,edge bb)
{
    return aa.cost<bb.cost;
}
int fa[105];
int Find(int x)
{
    if(fa[x]==x) return x;
    else return fa[x]=Find(fa[x]);
}

int main()
{
    scanf("%d",&n);
    m=n*(n-1)/2;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].cost,&a[i].flag);
    }
    sort(a,a+m,cmp);
    for(int i=0;i<=n;i++)
    {
        fa[i]=i;
    }
    int cnt=0;
    int ans=0;
    for(int k=0;k<m;k++)
    {
        int x=a[k].x;
        int y=a[k].y;
        int flag=a[k].flag;
        if(flag==1)
        {
            int aa=Find(x);
            int bb=Find(y);
            if(aa!=bb)
            {
                cnt++;
                fa[aa]=bb;
                if(cnt==n-1)
                {
                    break;
                }
            }
        }
    }
    if(cnt<n-1)
    {
        for(int k=0;k<m;k++)
        {
            int x=a[k].x;
            int y=a[k].y;
            int flag=a[k].flag;
            int cost=a[k].cost;
            if(flag==0)
            {
                int aa=Find(x);
                int bb=Find(y);
                if(aa!=bb)
                {
                    cnt++;
                    ans+=cost;
                    fa[aa]=bb;
                    if(cnt==n-1)
                    {
                        break;
                    }
                }
            }
        }
    }
    printf("%d\n",ans);


    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值