题意:给定一棵树,每个节点都有一个权值,给定出发点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;
}