[每日一題]:[Usaco2008Nov]安慰奶牛

題目:

樣例:

藍橋杯上的樣例是錯誤的,以後從網上查了一下,下面附上正確的樣例:

Sample Input
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

Sample Output
176

析題得侃:

這道題真的是有點難懂呀,對語文很差的我來講簡直太難了。
不得已,只能參考網上大佬的解釋了。
大體就是說:
一個牛從一個起點出發,遍歷整棵樹以後再回到起點,直到離開整棵樹(這句是本身猜的)
而後求一下最小的花費(每一個節點上有權值,每條路徑上也有花費的時間,知足最優的一種方案)

考察點: 最小生成樹

侃侃題解:

咱們最終求得是走完全部點後又回到起點的一條路線,假設咱們從 A -- > B,最後再從 B -- > A
那咱們所花費的代價就是 A + W(A,B) + B + B + W(B,A) + A
那麼能夠得知樹上的每一條邊應該都是這樣的。
因此咱們能夠按照這個新的權值進行建一棵最小生成樹便可。

另外,最後還要 + 最小的節點權值,我想是由於咱們最後離開全部的奶牛時還須要安慰一下起點處的奶牛
(若有更合適的解釋,但願大佬必定告訴我,在此萬分感謝)

Code:

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 2e5 + 10;

typedef long long LL;

struct node {
	LL u,v,w;
}cow[maxn];

bool cmp(node a,node b) {
	return a.w < b.w;
}

LL value[maxn],fa[maxn];

int n,p;

LL get(int x) {
	return x == fa[x] ? x : fa[x] = get(fa[x]);
}

void Union(int x,int y) {
	int xx = get(x);
	int yy = get(y);
	if(xx == yy) return ;
	fa[yy] = xx;
	return ; 
}

int main(void) {
	LL minValue = INF;
	scanf("%d%d",&n,&p);
	for(int i = 1; i <= n; i ++) {
		fa[i] = i;
	}
	// 尋找最小的節點做爲出發地 
	for(int i = 1; i <= n; i ++) {
		scanf("%lld",&value[i]);
		minValue = min(value[i],minValue);
	}
	int u,v,w;
	// 根據節點與邊之間的關係找到新的權值,更適合創建生成樹 
	for(int i = 1; i <= p; i ++) {
		scanf("%d%d%d",&u,&v,&w);
		cow[i].w = value[u] + value[v] + 2 * w;
		cow[i].u = u,cow[i].v = v;
	}
	sort(cow + 1,cow + 1 + p,cmp);
	LL sum = 0;
	
	for(int i = 1; i <= p; i ++) {
		int x = cow[i].u,y = cow[i].v,w = cow[i].w;
		if(get(x) == get(y)) continue;
		Union(x,y);
		sum += cow[i].w; 
	}
	
	printf("%lld\n",sum + minValue);
	return 0;
}

後記:

題都沒讀懂,樣例也沒推出來(雖說是錯的),hh,有點丟人,仍是本身太菜了。
收穫的地方感受就是更加了解怎樣去生成一個最小樹,怎麼樣更加合適,只有找
到合適的權值,咱們所求得的最小生成樹才更有意義。
也算複習了一下最小生成樹。
加油!
相關文章
相關標籤/搜索