Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5888 | Accepted: 3389 |
Description
Input
Output
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
Source
Ural State University Internal Contest October'2000 Students Session
题目大意:
一家公司要举办年会,公司有n个人,每个人有价值vi,这家公司有严格的等级制度,参加活动时,不能同时出现a和a的直接上司,求最大价值总和
解题思路:
下属关系属于一个树形(森林)结构,因为除了boss(们)每个人有一个上司,可以连一条边,dp[i][j]表示第i人参加(j==1)或者不参加(j==0)他和的他的子树所能获得的最大价值,那么dp[i][0]=sigema(max(dp[j][0],dp[j][1]))(j是子节点),dp[i][1]=v[i]+sigema(dp[j][0])(j是子节点),要求的就是max(dp[1][0],dp[1][1]);
p.s.注意有多个没有上司的boss根节点。
//使用向量124ms,链表做109ms,差的不多 #include<stdio.h> #include<map> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<iostream> #define maxn 6005 #define c(a) memset(a,0,sizeof(a)) #define c_1(a) memset(a,-1,sizeof(a)) using namespace std; vector<int>cl[maxn]; int dp[maxn][2]; short r[maxn]; bool v[maxn]; int dfs(int i, int j) { if (dp[i][j] != -1)return dp[i][j]; int ans = 0; if (j == 0) { for (int k = 0; k < cl[i].size(); k++) { int a = dfs(cl[i][k], 0); int b = dfs(cl[i][k], 1); ans += max(a, b); } return dp[i][j] = ans; } else { ans+=r[i]; for (int k = 0; k < cl[i].size(); k++) { ans += dfs(cl[i][k], 0); } return dp[i][j] = ans; } } int main() { int n; while (scanf("%d", &n)==1) { c(r); c_1(dp); c(v); for (int i = 0; i<=n; i++)cl[i].clear(); int a, b; for (int i = 1; i <=n; i++) scanf("%d", &r[i]); while(scanf("%d%d", &a, &b)==2&&a&&b) { cl[b].push_back(a); v[a] = 1; } for (int i = 1; i <= n; i++)if (cl[i].size() == 0) { dp[i][0] = 0; dp[i][1] = r[i]; } int x=0; for (int i = 1; i <= n; i++)if (!v[i]) x = x+max(dfs(i, 1), dfs(i, 0)); printf("%d\n",x); } }