반응형

문제 출처 :


https://www.acmicpc.net/problem/2213


알고리즘 분석 :


문제 해결에 필요한 사항

1. 트리

2. Dynamic Programming


이 문제는 전형적인 트리 DP 문제이다.


1. 현재 노드를 사용한다면 다음 노드는 사용하지 않고, 

2. 현재 노드를 사용하지 않는다면 다음 노드를 사용하거나 하지 않을때 중 최댓값을 찾아주면 된다.


이 과정을 재귀를 이용하여 문제를 해결하고 그때마다의 결과를 dp에 저장하여 메모이제이션을 해준다.



두번째로 이문제는 그렇게 정답을 찾아냈다면 추적까지 해보라는 문제이다.


추적을 할 때는 만약 현재 노드를 사용하고 있다면 다음 노드는 무조건 사용되지 않고 있을 것이고,


현재 노드가 사용되고 있지 않다면, 

이때는 dp값을 확인하여 다음 값을 사용할 때 dp값이 더 높다면 다음값을 사용해주고 

그렇지 않다면 다음 값을 사용하지 않는 방식으로 추적을 해나간다.



이 문제를 풀며 상당히 많이 틀렸는데, 조심해야 할 점을 말해보자면



   if(chk)

       ret = value[here];

    

   else ret = 0;


   for (auto next : vc[here])

   {

      if (next == prev)

         continue;


      if (chk)

         ret += dfs(here, next, 0);


      else

         ret += max(dfs(here, next, 0), dfs(here, next, 1));

   }



위와 아래 코드는 완전 다름을 알고 있어야 한다.



   else ret = 0;


   for (auto next : vc[here])

   {

      if (next == prev)

         continue;


      if (chk)

      {  

         ret = value[here];    

         ret += dfs(here, next, 0);

      }

      else

         ret += max(dfs(here, next, 0), dfs(here, next, 1));

   }



첫번째 코드와 가장 결정적인 차이는 if(next == prev)에 걸리게 되면 ret = value[here]를 받지 못하는 상황이 나오기 때문에


무조건 전처리를 해두는 것이 맞다.



유사문제로 


[1949번] 우수 마을 :: http://www.crocus.co.kr/636을 풀어보자.

 
















소스 코드 : 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <memory.h>
 
using namespace std;
 
int value[10002];
int dp[10002][2];
vector<int> vc[10002];
vector<int> ans;
 
int dfs(int prev, int here, bool chk)
{
   int &ret = dp[here][chk];
 
   if (ret != -1)
      return ret;
 
   if(chk)
       ret = value[here];
    
   else ret = 0;
 
   for (auto next : vc[here])
   {
      if (next == prev)
         continue;
 
      if (chk)
         ret += dfs(here, next, 0);
 
      else
         ret += max(dfs(here, next, 0), dfs(here, next, 1));
   }
 
   return ret;
}
 
void trace(int prev, int here, bool chk)
{
   if (chk)
   {
      ans.push_back(here);
      for (auto next : vc[here])
      {
         if (next == prev)
            continue;
 
         trace(here, next, 0);
      }
   }
 
   else
   {
      for (auto next : vc[here])
      {
         if (next == prev)
            continue;
 
         if (dp[next][1>= dp[next][0])
            trace(here, next, 1);
         else
            trace(here, next, 0);
      }
   }
}
int main()
{
   memset(dp, -1sizeof(dp));
 
   int n;
   scanf("%d"&n);
 
   for (int i = 1; i <= n; i++)
      scanf("%d"&value[i]);
 
   for (int i = 0; i < n - 1; i++)
   {
      int from, to;
      scanf("%d %d"&from, &to);
 
      vc[from].push_back(to);
      vc[to].push_back(from);
   }
 
   int a = dfs(-110);
   int b = dfs(-111);
 
   if (a >= b)
      trace(-110);
   else
      trace(-111);
 
   sort(ans.begin(), ans.end());
 
   printf("%d\n", max(a, b));
   for (auto i : ans)
      printf("%d ", i);
 
   return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus


반응형

'Applied > 알고리즘 문제풀이' 카테고리의 다른 글

[12605번] 단어순서 뒤집기  (0) 2017.10.09
[13334번] 철로  (0) 2017.09.25
[14716번] 현수막  (0) 2017.09.25
[3184번] 양  (0) 2017.09.24
[11313번] Best Buddies  (0) 2017.09.23