4.15Codeforces Round #635 (Div. 2)C.Linova and Kingdom題解

題目鏈接:https://codeforces.ml/contest/1337/problem/C

大意:給出n,k和一個點數量爲n的樹,讓其中k個結點變爲工業城市,其餘爲旅遊城市。而每個工業城市到根節點1的路徑上存在的旅遊城市數量之和求最大,並輸出最大值。

樣例:
Examples
inputCopy
7 4
1 2
1 3
1 4
3 5
3 6
4 7
outputCopy
7
inputCopy
4 1
1 2
1 3
2 4
outputCopy
2
inputCopy
8 5
7 5
1 7
6 1
3 7
8 3
2 1
4 5
outputCopy
9

這個題我們可以先不考慮兩個工業城市連成一個線,讓他們對答案的貢獻都不變。

以樣例一爲例子:

我們什麼都不管就xjb往深度高的結點去貪心看看:可以,得出的是7。但是我們貪心取得是當前貢獻最大,所以先貪567,他們三個用完再去考慮深度爲2的234.

如果我們用樣例3爲例子,就會發現一個問題:
在這裏插入圖片描述

這是第三樣例的圖,我們可以看到他們的深度d[i],從1到8分別是:
i 1 2 3 4 5 6 7 8
d[i] 0 1 2 3 2 1 1 3

從貪心的想法是:先要了4和8,ans現在等於6了,如果現在我們選了5會怎麼樣?會導致4的貢獻-1,應該說:選了5,5後面有多少個點貢獻就會減一。

爲什麼呢?因爲是貪心深度高的點,既然已經選到了5這個點,那麼必定他後面的點都已經選完了纔會去選他的。

所以現在5這個點的貢獻還是不是2?不是了,他的貢獻已經是一了。

貪心結論(策略):
深度d[i]-=後面的點down[i];
sort(d);
取前k大。

代碼:

//覺得有用的麻煩點個讚唄
typedef unsigned long long ULL;
typedef long long LL;
struct note
{
	int from,to;
};
vector<int >point[200001];
LL d[200001];
int down[200001];
void dfs(int a,int last)
{
	int len=point[a].size();
	for(int time=0;time<len;time++)
	{
		if(point[a][time]==last)continue;
		d[point[a][time]]=d[a]+1;
		dfs(point[a][time],a);
	}
}
void look(int a,int last)
{
	int len=point[a].size();
	int res=len;
	if(a!=1)res--;
	for(int time=0;time<len;time++)
	{
		if(point[a][time]==last)continue;
		look(point[a][time],a);
		res+=down[point[a][time]];
	}
	down[a]=res;
}
int main()
{
	int n,k;
	cin>>n>>k;
	for(int time=1;time<n;time++)
	{
		int from,to;
		cin>>from>>to;
		point[from].push_back(to);
		point[to].push_back(from);
	}
	d[1]=0;
	dfs(1,1);
	look(1,1);
	for(int time=1;time<=n;time++)
	{
		d[time]-=down[time];
	}
	sort(d+1,d+n+1);
	LL ans=0;
	for(int time=n;time>n-k;time--)ans+=d[time];
	printf("%lld\n",ans);
	return 0;
}
//覺得有用的麻煩點個讚唄

還要注意一個問題:ans要開LL,不然會爆炸哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章