codevs 1380 没有上司的舞会 - 树形动态规划
题目描述 Description
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。
输入描述 Input Description
第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0,0。
输出描述 Output Description
输出最大的快乐指数。
样例输入 Sample Input
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0
样例输出 Sample Output
5
数据范围及提示 Data Size & Hint
各个测试点1s
按照这个关系建一棵树,然后进行树归,用f[i]表示i职员参加舞会的最大快乐指数之和,g[i]表示i职员不参加舞会的最大快乐指数之和。那么有f[i]为所有i的子节点的g[son[i]]的和,g[i]是i的子节点的g[son[i]]和f[son[i]]最大值的和。
最后的答案在f[1]和g[1]中找最大值。
Code
1 /** 2 * codevs 3 * Problem#1380 4 * Accepted 5 * Time:10ms 6 * Memory:492k 7 */ 8 #include<iostream> 9 #include<sstream> 10 #include<algorithm> 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<cctype> 15 #include<cmath> 16 #include<ctime> 17 #include<map> 18 #include<stack> 19 #include<set> 20 #include<queue> 21 #include<vector> 22 #ifndef WIN32 23 #define AUTO "%lld" 24 #else 25 #define AUTO "%I64d" 26 #endif 27 using namespace std; 28 typedef bool boolean; 29 #define inf 0xfffffff 30 #define smin(a, b) (a) = min((a), (b)) 31 #define smax(a, b) (a) = max((a), (b)) 32 template<typename T> 33 inline boolean readInteger(T& u) { 34 char x; 35 int aFlag = 1; 36 while(!isdigit((x = getchar())) && x != '-' && x != -1); 37 if(x == -1) { 38 ungetc(x, stdin); 39 return false; 40 } 41 if(x == '-') { 42 aFlag = -1; 43 x = getchar(); 44 } 45 for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0'); 46 u *= aFlag; 47 ungetc(x, stdin); 48 return true; 49 } 50 51 typedef class Edge { 52 public: 53 int end; 54 int next; 55 Edge(const int end = 0, const int next = 0):end(end), next(next) { } 56 }Edge; 57 58 typedef class MapManager { 59 public: 60 int ce; 61 int *h; 62 Edge *edge; 63 MapManager():ce(0), h(NULL), edge(NULL) { } 64 MapManager(int points, int edges):ce(0) { 65 h = new int[(const int)(points + 1)]; 66 edge = new Edge[(const int)(edges + 1)]; 67 memset(h, 0, sizeof(int) * (points + 1)); 68 } 69 70 inline void addEdge(int from, int end) { 71 edge[++ce] = Edge(end, h[from]); 72 h[from] = ce; 73 } 74 75 Edge& operator [](int pos) { 76 return edge[pos]; 77 } 78 }MapManager; 79 #define m_begin(g, i) (g).h[(i)] 80 81 int n; 82 int *val; 83 MapManager g; 84 int *f, *g1; 85 int root; 86 87 inline void init() { 88 readInteger(n); 89 val = new int[(const int)(n + 1)]; 90 g = MapManager(n, n); 91 f = new int[(const int)(n + 1)]; 92 g1 = new int[(const int)(n + 1)]; 93 for(int i = 1; i <= n; i++) 94 readInteger(val[i]); 95 int sum = 0; 96 for(int i = 1, a, b; i < n; i++) { 97 readInteger(a); 98 readInteger(b); 99 sum += a; 100 g.addEdge(b, a); 101 } 102 root = n * (n + 1) / 2 - sum; 103 } 104 105 void treedp(int node, int fa) { 106 g1[node] = 0; 107 f[node] = val[node]; 108 for(int i = m_begin(g, node); i != 0; i = g[i].next) { 109 int& e = g[i].end; 110 if(e == fa) continue; 111 treedp(e, node); 112 g1[node] += max(g1[e], f[e]); 113 f[node] += g1[e]; 114 } 115 } 116 117 inline void solve() { 118 treedp(root, 0); 119 printf("%d", max(g1[root], f[root])); 120 } 121 122 int main() { 123 init(); 124 solve(); 125 return 0; 126 }