【最小生成树】安慰员工

安慰员工(cheer.pas/c/cpp) 
 
【题目描述】 
LongDD 变得非常懒, 他不想再继续维护供员工之间供通行的道路. 道路被用来连
接N(5 <= N <= 10,000)个房子, 房子被连续地编号为 1..N. 每一个房子都是一个
员工的家. LongDD计划除去 P(N-1 <= P <= 100,000)条道路中尽可能多的道路, 但
是还要保持房子之间的连通性. 你首先要决定那些道路是需要保留的 N-1 条道路. 
 
第j条双向道路连接了房子 S_j和E_j (1 <= S_j <= N; 1 <= E_j <= N; S_j != E_j),
而且走完它需要L_j (0 <= L_j <= 1,000)的时间.没有两个房子是被一条以上的道
路所连接. 
 
员工们非常伤心, 因为她们的交通系统被削减了. 你需要到每一个员工的住处去安
慰她们. 每次你到达第 i 个房子的时候(即使你已经到过), 你必须花去 C_i (1 <= 
C_i <= 1,000)的时间和员工交谈. 
 
你需要从某一个房子出发(这是供你选择的),并最终回到这个房子。期间,你要经
过每个房子至少一次,并且当你经过某个房子的时候,你必须和这个房子里的员工
交谈(即使你已经到过). 
 
假设LongDD 采纳了你的建议, 请计算出使所有员工都被安慰的最少时间. 
 
【输入格式】 
* 第 1 行: 用空格隔开的两个整数 N和P 
* 第 2..N+1 行: 第i+1 行包含了一个整数: C_i 
* 第 N+2..N+P+1 行: 第 N+j+1 行包含用空格隔开的三个整数: S_j, E_j 和 L_j 
 
【输入样例】 
5 7 
10 
10 
20 

30 
1 2 5 
2 3 5 
2 4 12 
3 4 17 
2 5 15 
3 5 6 

4 5 12 

这道题比较水但是当时出现了特别奇葩的错误

教训:记得判断边界(无论你如何相信不会超出边界 但很有可能他还是会超出边界)

裸的最小生成树吧

由于去掉边后形成的是一个有回路的树

每条边必然被使用两次

所以边权值为二倍长度 + 两端点的代价

而出发点并没有计算在内 所以最后加上出发点的代价

也就是所有代价中最小的一个

代码如下

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;


int N, P;
int Cost[100005];
int Father[100005];
int Low = 0x3f3f3f3f;
int Mst();
void init();
int Get_Father(int x);
int ans;
struct Edge
{
    int u, v, d;
    bool operator < (const Edge &N) const
    {
        return d < N.d;
    }
}edge[1000005];


inline void Ins(int k)
{
    int u, v, d;
    scanf("%d%d%d", &u, &v, &d);
    d = d + d + Cost[u] + Cost[v];
    edge[k].u = u;
    edge[k].v = v;
    edge[k].d = d;
}


void init()
{
    for(int i = 1; i <= N; i++)
    {
        Father[i] = i;
    }
    return;
}


inline int Get_Father(int x)
{
    if (Father[x] != x)
    {
        return Father[x] = Get_Father(Father[x]);
    }
    return x;
}


void init_file()
{
    freopen("cheer.in", "r", stdin);
    freopen("cheer.out", "w", stdout);
}


void read_data()
{
    scanf("%d%d", &N, &P);
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", Cost + i);
        Low = min(Low, Cost[i]);
    }
    for(int i = 1; i <= P; i++)
        Ins(i);
    sort(edge + 1, edge + 1 + P);
}


int Mst()
{
    init();
    int time = 1;
    int ans = edge[1].d;
    int fx = Get_Father(edge[1].u);
    int fy = Get_Father(edge[1].v);
    int V_t = 0;
    Father[fx] = fy;
    time++;
    while(V_t + 1 < N && time <= P)
    {
        int fx = Get_Father(edge[time].u);
        int fy = Get_Father(edge[time].v);
        if (fx != fy)
        {
            Father[fx] = fy;
            ans += edge[time].d;
            ++V_t;
        }
        ++time;
    }
    return ans;
}


void work()
{
    printf("%I64d", (long long)(Mst() + Low));
}


int main()
{
    init_file();
    read_data();
    work();
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值