zoukankan      html  css  js  c++  java
  • 试题 算法训练 安慰奶牛

     
    资源限制
    时间限制:1.0s   内存限制:256.0MB
     
    问题描述

    Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路。道路被用来连接N个牧场,牧场被连续地编号为1到N。每一个牧场都是一个奶牛的家。FJ计划除去P条道路中尽可能多的道路,但是还要保持牧场之间 的连通性。你首先要决定那些道路是需要保留的N-1条道路。第j条双向道路连接了牧场Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N; Sj != Ej),而且走完它需要Lj的时间。没有两个牧场是被一条以上的道路所连接。奶牛们非常伤心,因为她们的交通系统被削减了。你需要到每一个奶牛的住处去安慰她们。每次你到达第i个牧场的时候(即使你已经到过),你必须花去Ci的时间和奶牛交谈。你每个晚上都会在同一个牧场(这是供你选择的)过夜,直到奶牛们都从悲伤中缓过神来。在早上 起来和晚上回去睡觉的时候,你都需要和在你睡觉的牧场的奶牛交谈一次。这样你才能完成你的交谈任务。假设Farmer John采纳了你的建议,请计算出使所有奶牛都被安慰的最少时间。

    输入格式

    第1行包含两个整数N和P。

    接下来N行,每行包含一个整数Ci

    接下来P行,每行包含三个整数Sj, Ej和Lj

    输出格式
    输出一个整数, 所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间)。
     
    样例输入
    5 6
    10
    10
    20
    6
    30
    1 2 5
    2 3 5
    2 4 12
    3 4 17
    2 5 15
    3 5 6
     
    样例输出
    176
     
    数据规模与约定

    5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。

    题目一边读下来就觉得很复杂,不知道最小生成树的源点应该设在哪,百度了一下才知道,原来自己多画几个图就能明白个中奥妙,不知道怎么做的时候一定要动手动手,写写画画理清思路!一点就通

    于是通过观察可以发现:各个结点的访问次数恰好和其邻边数相等,只有源点的访问次数多了一次,那么只要选取点权最小的结点作为源点,就能得到答案,即所需最少时间是 min + Kruskal()。

    需要注意的是,因为要回到源点,所以每条边都会经过两次,并且除了边权,结点也有权值,我们需要更改边权为 L*2+C1+C2(即边权*2+这条边的两个端点的权值)。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <string>
     6 #include <cmath>
     7 #include <algorithm>
     8 #define INF 0x3f3f3f3f
     9 
    10 using namespace std;
    11 typedef long long ll;
    12 const ll mod=1000000007;
    13 const int max_n=10005;
    14 const int max_p=100005;
    15 
    16 int par[max_n];//根结点 
    17 int n, p;//牧场数(结点),道路数(边) 
    18 int c[max_n];//谈话时间 
    19 
    20 struct edge {
    21     int from, to, cost;//起点,终点,边权 
    22 }e[max_p];
    23 
    24 int cmp(edge x, edge y) {
    25     return x.cost<y.cost;
    26 }
    27 //初始化根结点为该结点本身 
    28 void init() {
    29     for(int i=1; i<=n; i++) {
    30         par[i]=i;
    31     }
    32 }
    33 //查找根结点 
    34 int fid(int x) {
    35     if(par[x]==x) return x;
    36     else return par[x]=fid(par[x]);
    37 }
    38 //合并两集合 
    39 void unite(int x, int y) {
    40     par[y]=par[x];
    41 }
    42 //最小生成树 
    43 int kruskal() {
    44     sort(e, e+p, cmp);//把边按权值从小到大排序
    45     int cnt=0;//构建的最小生成树加入的边数 
    46     int ans=0;//最小生成树的边权总和 
    47     for(int i=0; i<p; i++) {
    48         if(cnt==n-1) break;//已构建好最小生成树
    49         int a=fid(e[i].from);
    50         int b=fid(e[i].to);
    51         if(a!=b) {
    52             unite(a, b);
    53             ans+=e[i].cost;
    54             cnt++;
    55         }
    56     }
    57     return ans;
    58 }
    59 
    60 int main() {
    61     int minc=1005;//最小谈话时间 
    62     int u, v, w;
    63     cin>>n>>p;
    64     for(int i=1; i<=n; i++) {
    65         scanf("%d", &c[i]);
    66         minc=min(minc, c[i]);
    67     }
    68     for(int i=0; i<p; i++) {
    69         scanf("%d %d %d", &u, &v, &w);
    70         e[i].from=u;
    71         e[i].to=v;
    72         e[i].cost=w*2+c[u]+c[v];
    73     }
    74     init(); 
    75     int ans=minc+kruskal();
    76     printf("%d
    ", ans);
    77     return 0;
    78 }
  • 相关阅读:
    泛型与非泛型
    C# 调用CMD,执行DOS命令
    数据库设计随笔(ZZ)
    关于三层开发(zz)
    三层架构学习(转)
    Node.js & child_process All In One
    HTML5 Canvas Tag Cloud All In One
    macOS & VSCode terminal show current git branch All In One
    飞书 excel 固定列 All In One
    git diff one of committed file All In One
  • 原文地址:https://www.cnblogs.com/wwqzbl/p/13522034.html
Copyright © 2011-2022 走看看