Codeforces 77C 트리 dp + 욕심

제목 링크: 클릭하여 링크 열기
제목:
n개 점을 지정,
점당 콩 수량
아래는 나무입니다.
다시 시작점을 드리도록 하겠습니다.
점마다 그 점을 찍은 콩을 하나씩 먹는다.
물음: 출발점으로 돌아가면 최대 몇 알의 콩을 먹을 수 있느냐
사고방식: 트리 dp
현재 노드 u에 대해 먼저 하위 노드 v를 모두 한 번 걸어라.
그리고 u시에 콩이 없거나 v시에 콩이 없을 때까지 (u, v) 사이를 왕복한다.
dp[u]는 u점의 최대치를 나타낸다.a[u]는 u점에 남은 콩의 수다.
#include 
#include 
#include 
#include 
using namespace std;
#define N 100002
#define ll long long
int n, root;
vectorG[N];
bool cmp(int a, int b){return a>b;}
int a[N];
ll dp[N];//dp[i]      i     
void dfs(int u, int fa){
    dp[u] = 1;
	vectors;
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i]; if(v == fa || a[v] == 0)continue;
		a[v]--;
		dfs(v, u);
        if(dp[v])
           s.push_back(dp[v]);
    }
	sort(s.begin(), s.end(),cmp);
	for(int i = 0; a[u] && i < s.size(); i++) a[u]--, dp[u] += s[i] +1;
    for(int i = 0; a[u] && i < G[u].size(); i++)
    {
        int v = G[u][i]; if(v == fa || a[v] == 0)continue;
        dp[u] += 2LL * min(a[u], a[v]);
        a[u] -= min(a[u], a[v]);
    }
}
int main() {
    int i, u, v;
    while(~scanf("%d", &n)) {
        for(i = 1; i <= n; i++) scanf("%d",&a[i]), G[i].clear();
        for(i = 1; i < n; i++)
        {
            scanf("%d %d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        scanf("%d",&root);
        dfs(root, root);
        cout<

좋은 웹페이지 즐겨찾기