试题 算法训练 安慰奶牛

 
资源限制
时间限制: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\n", ans);
77     return 0;
78 }

 

 

posted @ 2020-08-18 13:06  自在逍遥处  阅读(380)  评论(2编辑  收藏  举报