CF767C Garland
生活随笔
收集整理的這篇文章主要介紹了
CF767C Garland
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一道樹形DP
\(Translate\)
有一顆\(n\)個節點的樹
第\(i\)個節點權值為\(a_i\) \((n<=10^6,-100<=a_i<=100)\)
問是否能夠刪除掉兩條邊,使得該樹分成三個不為空的部分,并且每部分權值之和相等。
無解輸出\(?1\) 否則輸出要刪除邊\((u?>v)\)的v節點序號。
\(Solution\)
很明顯我們可以在\(DFS\)遍歷樹的時候記錄子樹和這個節點的權值和,我們要要將這個樹分成三部分,每部分權值和都為\(Sum/3\),所以當我們找到當前的和為\(Sum/3\)時,就可以\(cnt++\),然后記錄下這個點,千萬不要忘了將現在的求和數組清零,因為如果從這里斷開,這個節點對它的父節點將沒有貢獻,最后找完,如果\(cnt<=2\),說明分成的子樹個數\(<=2\)而不是斷邊\(<=2\),這點要注意。這時候輸出\(-1\)即可,否則說明這顆樹可以分成三部分,輸出\(ans[1],ans[2]\)即可。
剪枝
這個題剪枝十分明顯,也比較好想,我們只要在\(dp\)前判斷所有的權值和能否被\(3\)整除即可,優化十分有效。
\(Code\)
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define LL long long #define maxn 1000001 using namespace std; struct Edge{int nxt,to,from; }edge[maxn*2];//因為這是個樹 int num_edge,head[maxn],a[maxn],n,fa,total,sum,cnt,ans[maxn],ksum[maxn]; inline int qread(){char ch=getchar();int f=1,x=0;while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f; } inline void addedge(int from,int to){ //加上from的原因是我們要輸出他的from edge[++num_edge].nxt=head[from];edge[num_edge].from=from;edge[num_edge].to=to;head[from]=num_edge; } int dfs(int x,int fath){ksum[x]=a[x];for(int i=head[x];i;i=edge[i].nxt){//找祖先 int y=edge[i].to;if(y!=fath){dfs(y,x);ksum[x]+=ksum[y];}}if(ksum[x]==sum){ //當滿足了之后 cnt++;ans[cnt]=x;ksum[x]=0;} } int main(){n=qread();//快讀,否則的話大數據卡死 for(int i=1;i<=n;i++){int x;x=qread();a[i]=qread();if(x!=0) {addedge(i,x);addedge(x,i);}else fa=i;total+=a[i];}if(total%3!=0) printf("-1\n");else{sum=total/3;dfs(fa,0);if(cnt>=3) printf("%d %d\n",ans[2],ans[1]);else printf("-1\n");}return 0; }\(Addition\)
在寫這里之前還有一個問題不太理解,那就是為什么要寫\(cnt>=3\)而不能寫\(cnt==3\),不是只會分成三個塊嗎?
下面這段代碼我倒是能理解
轉載于:https://www.cnblogs.com/Liuz8848/p/10876984.html
總結
以上是生活随笔為你收集整理的CF767C Garland的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode Divisor Gam
- 下一篇: VALSE2019总结(2)-以人为中心