hdu_3371 Connect the Cities

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3371

分析:

       题目大意:有n个城市,你可以链接的城市有m对。通过k条输入,可以知道哪些城市是连通的。要求使用最少的花费将所有城市连通起来,如果不能连起来则输出-1,能则输出最小花费。

      如下图,通过最后面的k行输入可得下图连通关系。

    由m,我们可以知道我们能连接的城市即花费。

     城市   城市  花费

      1          4         2

      2          6         1

      2          3         5

      3          4        33

所以,为使城市连通又要花费少,我们连接2,6;


      算法分析:使用并查集+贪心。连通的城市在一个集合里,对m条可以连接的边安费用从小到大排序。对m连接的连个城市做判断,如果在同一集合则不用连通,不再同一集合,就把集合合并,记录此时花费。m条边判断完后,看是否只有一个集合,是的话则意味着所有此时连通了。

我的代码:

#include<stdio.h>
#include<algorithm>
using namespace std;
#define MAXN 505
#define MAXM 25005
int f[MAXN];
int r[MAXM];
struct Node
{
    int p,q,c;
    //重定义< 然其按c从小到大排。
    bool operator <(const Node &x ) const{
        return c<x.c;
    }
};
Node a[MAXM];
void init(int n)
{
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        r[i]=1;
    }
}
int find(int n)  //找n所在集合。
{
    if(f[n]==n) return n;
    else return f[n]=find(f[n]);  //路劲压缩
}
void Union(int x,int y)  // x所在集合与y所在集合,合并。
{
    int a=find(x);
    int b=find(y);
    if(a==b) return ;
    else
    {
        if(r[a]<r[b])   //按秩合并,即将集合元素少得合并到元素多得集合里。
        {
            f[a]=b;
            r[b]+=r[a];
        }
        else
        {
            f[b]=a;
            r[a]+=r[b];
        }
    }

}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        init(n); //初始化,并查集。
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a[i].p,&a[i].q,&a[i].c);
        }
        sort(a,a+m);  //对m条边排序。
        while(k--)  //用并查集,求出集合。
        {
            int num,e,e1;
            scanf("%d%d",&num,&e);
            for(int i=1;i<num;i++) //已经输入了a,少输入一个。
            {
                scanf("%d",&e1);
                Union(e,e1);
            }
        }
        int tot=0; //总花费。
        for(int i=0;i<m;i++)  //在 a 数组中选出可用的边链接集合。
        {
            int ind1=find(a[i].p);
            int ind2=find(a[i].q);
            if(ind1==ind2) continue;
            else
            {
                tot+=a[i].c;
                Union(ind1,ind2);
            }
        }
        int root_num=0;
        for(int i=1;i<=n;i++) //判断集合个数
        {
            if(f[i]==i) root_num++;
            if(root_num>1) break;
        }
        if(root_num>1) //集合个数>1,即城市没有链接。
        {

            printf("-1\n");
        }
        else
        {
            printf("%d\n",tot);
        }

    }

    return 0;
}
总结:其实本题还是挺简单的,与食物链那种题目相比。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值