題意:給定一棵樹,每個節點都有一個權值,給定出發點a,從a開始,到達每個點每個點就獲得該點的一個權值(該節點相應減少一個),問最多可以得到多少值。。。
分析: dfs,將根節點的值增加1,然後對每顆子樹的操作都一樣,每次選擇子樹可能獲得更多的優先選擇,最後父節點和子節點可能還有剩餘,還可以來回走動。。。
無語說是樹形dp。。額。。。
代碼:寫得好戳啊。。。因為少了幾個int64,wa了一大片。。。
#include <iostream>#include<stdio.h>#include<cmath>#include<vector>#include<algorithm>using namespace std;const int N=100010;struct node{ int p; __int64 a, num; //num子樹的最大可能}tmp;int n, flag[N];__int64 a[N], ans;vector<node> b[N];int cmp(const node &a, const node &b){ return a.num > b.num;}__int64 dfs(int p){ vector<node>::iterator it; int cnt=0; for(it=b[p].begin(); it!=b[p].end(); it++) { if(flag[(*it).p]==0) { flag[(*it).p] = 1; (*it).num = dfs((*it).p); flag[(*it).p] = 0; (*it).a = a[(*it).p]; cnt++; } } if(cnt==0) { return 0; } sort(b[p].begin(), b[p].end(), cmp); __int64 num=0; a[p]--; for(it=b[p].begin(); a[p]>0&&it!=b[p].end()&&(*it).num>0; it++) { if(flag[(*it).p]==0) //(*it).a始終是>=1的。。 { (*it).a--; a[p]--; num += (*it).num+2; } } __int64 num1 = 0; for(it=b[p].begin(); it!=b[p].end(); it++) { if(flag[(*it).p]==0 && (*it).a>0) { num1 += (*it).a; } } num += min((__int64)a[p], num1)*2; //這兩句 a[p] -= min((__int64)a[p], num1); //弄反了。。。 a[p]++; return num;}int main(){ int i, j, k, head; while(scanf("%d", &n)!=EOF) { for(i=1; i<=n; i++) { scanf("%I64d", &a[i]); flag[i] = 0; } for(i=1; i<=n-1; i++) { scanf("%d %d", &j, &k); tmp.p = k; tmp.a = a[k]; tmp.num = 0; b[j].push_back(tmp); tmp.p = j; tmp.a = a[j]; tmp.num = 0; b[k].push_back(tmp); } scanf("%d", &head); a[head]++; flag[head] = 1; ans = dfs(head); printf("%I64d\n", ans); for(i=1; i<=n; i++) { while(!b[i].empty()) { b[i].pop_back(); } } } return 0;}