cf 1059e 思维 贪心 树
參考博客:http://www.cnblogs.com/waldenlake/p/9750249.html
題意:將一棵n個點的帶權有根樹剖分成盡量少的鏈,使得
(1)鏈的兩個端點是祖先關系
(2)鏈含有的頂點個數小于等于L
(3)鏈上所有點的點權和小于等于S。
求出最少鏈的數量,如果無解輸出-1。N<=105
?
思路:
想法非常的新穎 ,根據子節點的情況來決定父節點是跟隨某個子節點繼續向上,還是自己獨立開始一段新的path。
但是!!!想想這個問題的性質,有個疑問:局部最優會導致全局最優嗎?答案是肯定的,所以,直接上貪心!
?
我們來看這個貪心的性質,就是有兩個葉子節點a,b,他們有公共的父節點c,沿著a,b一直向上尋找(不同問題有不同尋找方向,一般從下網上,但別被拘束),直到長度或者w超限,假設a能到c上面的一個節點,b卻能到c上面的三個節點,那么這三個節點劃分到b的path為最優,因為我總不至于能包含卻不去包含他們的。
就是說,即便先選了a,向上追溯并染色到了c上1點,后選了b,向上追溯并染色到了c上3點,我們不就是等于說,a的后半段不跟a了,改成屬于b的path。因為我們總是改變后半段的歸屬,右總是從葉子節點開始,所以這種貪心總是能得到更好的結果,而且保證最好的結果是總能出現的。
?
下面的代碼是可以hack的,因為沒有保證每次都是從葉子節點開始尋找,只要做一次bfs對層次作排序就能保證son總是出現father后
?
\沒想到div2最后一題居然這么簡單的貪心就可以解決。。還是思維不夠@#$%
?
#include<bits/stdc++.h> using namespace std;#define ll long long #define pb push_back #define mp make_pair #define fi first #define se second #define pii pair<int,int> #define all(v) v.begin(),v.end()const int N = 1E5+3;ll w[N],p[N]; int vis[N];int main(){ll n,l,s;cin>>n>>l>>s;int f=0;for(int i=1;i<=n;++i){cin>>w[i];if(w[i]>s)f=1;}for(int i=2;i<=n;++i)cin>>p[i];if(f){printf("-1\n");return 0;}int ans= 0 ;//其實還不太準確 要保證從葉子開始for(int i=n;i>=1;--i){if(vis[i]==0){ans++;int j = i;ll xl =l,xs= s;while(xs >= w[j] && xl>0 && j!=0){xs -= w[j]; vis[j]=1;xl--;j = p[j];}}}cout<<ans<<endl;return 0; }?
轉載于:https://www.cnblogs.com/wjhstudy/p/9766794.html
總結
以上是生活随笔為你收集整理的cf 1059e 思维 贪心 树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win11玩lol卡顿怎么解决(win1
- 下一篇: 电脑万能优盘驱动(硬盘万能驱动)