1. 程式人生 > >演算法訓練 安慰奶牛 最小生成樹

演算法訓練 安慰奶牛 最小生成樹

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

思路:好久沒搞圖論了...最小生成樹都快忘了...

這道題只要理解了題意就是一個Kruskal模板題,因為題中要求的是到每一個點都要安慰所在頂點的奶牛,而且每天晚上都會在同一個牧場過夜,

這就說明我們選定一個點出發遍歷完這棵生成樹後還要返回樹根,也就是每個邊都走了兩邊,並且所在頂點的度(除起始點)為多少,該點就走幾遍.

由於每一個點也有權值,所以真正的權值為 2*邊的權值+邊所連兩個頂點的值

對於選哪一個點做為起始點:因為要求最短時間,所以我們起始點的奶牛的安慰時間要最少即可.

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e4+10;
const int M=1e5+10;
int C[N],n,p,sum;
int pre[N];
struct node{
	int u,v,w;
}q[M];
int cmp(node x,node y)
{
	return x.w<y.w;
}
void build()
{
	for(int i=1;i<=n;i++)
	 pre[i]=i;
	 return ;
}
int find(int x)
{
	if(x==pre[x])
	return pre[x];
	else
	{
		pre[x]=find(pre[x]);
		return pre[x];
	}
}
int join(int x,int y)
{
	int f1=find(x);
	int f2=find(y);
	if(f1!=f2)
	{
		pre[f2]=f1;
		return 1;
	}
	return 0;
}
void Kruskal()
{
	int count=0;
	sum=0;
	for(int i=0;i<p;i++)
		{
			if(join(q[i].u,q[i].v))
			{
				count++;
				sum+=q[i].w;
			}
			if(count==n-1)
			break;
		}
		return ;
}
int main()
{
	int a,b,c;
	int ss=inf;
	scanf("%d%d",&n,&p);
	for(int i=1;i<=n;i++)
	{	scanf("%d",&C[i]);
		ss=min(ss,C[i]);
	}	
	for(int i=0;i<p;i++)
	{
		scanf("%d %d %d",&a,&b,&c);
		q[i].u=a;
		q[i].v=b;
		q[i].w=2*c+C[a]+C[b];
	 } 
	 sort(q,q+p,cmp);
	 build();
	 Kruskal();
	 printf("%d\n",sum+ss);
	 return 0;
}