安慰奶牛

安慰奶牛

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述
  Farmer John最近变得非常懒,他不想再继续维护供奶牛通行的道路。这些道路被用来连接N个牧场,牧场编号为1到N。每一个牧场是一个奶牛的家。FJ计划除去M条道路中尽可能多的道路,但是还要保持牧场之间的连通。因为奶牛们的交通系统被破坏了,所以她们非常伤心,于是,FJ决定去安慰她们。现在已知每条道路的起点S和终点E(1 <= S <= N,1 <= E <= N,S != E),以及走完这条路需要的时间L。当FJ到达第i个牧场的时候(即使已经到过),他必须花去Ci的时间和奶牛交谈。在早上出发和晚上回去的时候,他都需要和他所在牧场的奶牛交谈一次。假设一天可以谈完,谈完后必须回到早上出发的点(出发点可以任意选择),这样才算完成他的交谈任务。
  FJ想知道安慰所有的奶牛至少需要多长的时间,聪明的你能告诉他吗?
输入
多组测试数据。
对于每组数据,第1行包含两个整数N和M。
接下来N行,每行包含1个整数Ci(1<=Ci<=1000)。
接下来M行,每行包含三个整数S, E和L(1<=L<=1000)。
输出
输出一个整数, 表示所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间)。
样例输入
5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
4 5 12
样例输出
176

  

思路:这就是一道简单的最小生成树的问题可是我们要注意的是  当我们去了一个地方我们要走回来的所以我们要把两个点的距离乘2

然后求出最小的那个用时最短的牧场过夜 加上去就可以了 

下面看代码:

    1. #include<stdio.h>  
    2. #include<iostream>  
    3. #include<string.h>  
    4. #include<algorithm>  
    5.   
    6.   
    7. using namespace std;  
    8.   
    9. #define max(a,b)((a > b)?(a):(b))  
    10. #define MAX 0x7fffffff  
    11. struct node  
    12. {  
    13.     int u;  
    14.     int v;  
    15.     int cap;  
    16. }edge[100100];  //每条路的属性的  
    17. int d[100100];  
    18. int p[100100];   //记录每个点的值的  
    19. int f[100100];   //记录每个点的父亲节点的  
    20. int M, n, m;  
    21. bool cmp(node a,node b)  
    22. {  
    23.     return a.cap < b.cap;  
    24. }  
    25. void add(int from,int to,int cap)  
    26. {  
    27.     edge[M].u = from;  
    28.     edge[M].v = to;  
    29.     edge[M].cap = cap * 2 + p[from] + p[to]; //这个地方是去然后还得回来所以乘2  
    30.     M++;  
    31. }  
    32. int find(int x)  
    33. {  
    34.     if(f[x] == x)return f[x];  
    35.     return f[x] = find(f[x]);  
    36. }  
    37. void kruskal()  
    38. {  
    39.     int i;  
    40.     for(i = 1;i <= n;i++)  
    41.     {  
    42.         f[i] = i;  
    43.         d[i] = 0;  
    44.     }  
    45.     int u,v,fu,fv,sum = 0;  
    46.     for(i = 0;i < M;i++)  
    47.     {  
    48.         u = edge[i].u;  
    49.         v = edge[i].v;  
    50.         fu = find(u);  
    51.         fv = find(v);  
    52.         if(fu == fv)continue;//如果相同的话 那么久直接加就可以了  
    53.         sum += edge[i].cap;  
    54.         f[fu] = fv;   //这个地方别忘了 一定要把父亲节点给写了  
    55.         //d[u]++;  
    56.         //d[v]++;  
    57.     }  
    58.     int tmp = MAX;  
    59.     for(i = 1;i <= n;i++)  
    60.     {  
    61.         if(tmp > p[i])tmp = p[i];  
    62.     }  
    63.     printf("%d\n",sum + tmp);  
    64. }  
    65. int main()  
    66.   
    67. {  
    68.     int i;  
    69.     int s,t,c;  
    70.     while(~scanf("%d%d",&n,&m))  
    71.     {  
    72.         for(i = 1;i <= n;i++)  
    73.         {  
    74.             scanf("%d",&p[i]);  
    75.         }  
    76.         for(i = 0;i < m;i++)  
    77.         {  
    78.             scanf("%d%d%d",&s,&t,&c);  
    79.             add(s,t,c);  
    80.         }  
    81.         sort(edge,edge + M,cmp);  
    82.         kruskal();  
    83.     }  
    84.     return 0;  
    85.   
    86. }    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值