[图论]USACO Bad Cowtractors

本文介绍了一个有趣的问题:如何设计一个最昂贵的网络连接方案,确保所有节点都能连通但不形成环路。这是一个经典的图论问题,通过将最小生成树问题转变为最大生成树问题进行求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门:http://poj.org/problem?id=2377
Description


Bessie has been hired to build a cheap internet network among Farmer John’s N (2 <= N <= 1,000) barns that are conveniently numbered 1..N. FJ has already done some surveying, and found M (1 <= M <= 20,000) possible connection routes between pairs of barns. Each possible connection route has an associated cost C (1 <= C <= 100,000). Farmer John wants to spend the least amount on connecting the network; he doesn’t even want to pay Bessie.

Realizing Farmer John will not pay her, Bessie decides to do the worst job possible. She must decide on a set of connections to install so that (i) the total cost of these connections is as large as possible, (ii) all the barns are connected together (so that it is possible to reach any barn from any other barn via a path of installed connections), and (iii) so that there are no cycles among the connections (which Farmer John would easily be able to detect). Conditions (ii) and (iii) ensure that the final set of connections will look like a “tree”.
Input

  • Line 1: Two space-separated integers: N and M

  • Lines 2..M+1: Each line contains three space-separated integers A, B, and C that describe a connection route between barns A and B of cost C.
    Output

  • Line 1: A single integer, containing the price of the most expensive tree connecting all the barns. If it is not possible to connect all the barns, output -1.

翻译:农夫约翰雇了Bessie来为他的n个牲棚连上网。每个牲棚的编号是从1-n的。约翰已经做好了调查,并且找出了M条在任意两个牲棚之间可能的网线连路。每一个连路都会消耗Ci块钱。约翰自己想用最少的钱完成这项工作。
可是,Bessie知道约翰不会付他工资(信誉问题?),所以他决定让约翰花最多的钱。他现在决定:
1.让每个牲棚都连上网。(让约翰以为他做好了工作)
2.让连路无法构成环。(环很容易被约翰检测到)
3.让约翰花最多的钱。

请求出约翰花的最多的钱是多少。
如果牲棚无法被全部连通,输出-1.


题解:

每个节点都要连通,不能构成环,最大权值和为多少。。。
很明显,这是一道生成树问题,就是稍微变换了一下,最小生成树变成了最大生成树。
以Kruskal算法为例,只需要在根据边权排序时从升序变为降序即可。这样每次取出的边权为最大,满足Kruskal的原理。
最后,在判断连通时,只需遍历一次并查集,检查所有点是否属于同一个集合即可!


代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const ll N = 1005;
const ll M = N*N;
struct Edge
{
    ll u,v,w;
}edge[M];
ll cc;
ll n,m;
ll ans=0;
ll fa[N];
bool cmp(Edge x,Edge y)
{
    return (x.w>y.w);
}
ll getf(ll x)
{
    if(fa[x]!=x)
        fa[x]=getf(fa[x]);
    return fa[x];
}
int main()
{
    ll i,j,k;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
        cc++;
        ll a,b,c;
        scanf("%lld%lld%lld",&a,&b,&edge[cc].w);
        edge[cc].u=a;
        edge[cc].v=b;
    }
    sort(edge+1,edge+cc+1,cmp);
    for(i=1;i<=n;i++)
    {
        fa[i]=i;
    }   
    for(i=1;i<=cc;i++)
    {
        ll a=getf(edge[i].u);
        ll b=getf(edge[i].v);
        if(a!=b)
        {
            fa[a]=b;
            ans+=edge[i].w;
        }
    }
    for(int i=1;i<n;i++)
    {
        if(getf(i)!=getf(i+1))
        {
            printf("-1");
            return 0;
        }
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值