P1352 没有上司的舞会
这是我从luogu讲义弄下来的题目。
简化题意:
给你一棵树,每个结点有权值,父结点参加,子结点都不能参加。求最大权值和。
讲义告诉我们这道题用dp做。
本来我想的是用一维状态,结果发现错了。。。
加一维
也许加一维,问题就能更显然地解决,这道题数据范围不大,也说明要加一维了。。。
打出状态转移方程:
设\(dp[i][0]\)和\(dp[i][1]\)为\(i\)结点不去或去的最大权值和。
如果这个点不去,那么有:
\[dp[u][0] = \sum(max(dp[v][0], dp[v][1])), (u,v) \in E
\]
如果这个点去,就有:
\[dp[u][1] = weight[u] + \sum(dp[v][0]), (u,v) \in E
\]
有唯一的根节点为校长,就算不告诉我们也可以\(O(n)\)的找出来,建图后找到入度为0的点就是了。
最后的答案当然是校长去或不去两种情况的最大值。
我快读没写负数结果90。。。
代码:
#include<cstdio>
#include<algorithm>
const int maxn = 6005, INF = 1e9 + 7;
struct Edges
{
int next, to;
} e[maxn];
int head[maxn], tot;
int dp[maxn][2];
bool vis[maxn][2];
int weight[maxn];
int indegree[maxn];
int n, root;
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0')
{
if(ch == '-') s = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
ans = ans * 10 + ch - '0';
ch = getchar();
}
return s * ans;
}
void link(int u, int v)
{
e[++tot] = (Edges){head[u], v};
head[u] = tot;
}
int solve(int u, bool go)
{
if(vis[u][go]) return dp[u][go];
int ans;
if(go)
{
ans = weight[u];
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
ans += solve(v, 0);
}
}
else
{
ans = 0;
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
ans += std::max(solve(v, 0), solve(v, 1));
}
}
vis[u][go] = true;
return dp[u][go] = ans;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++) weight[i] = read();
for(int i = 1; i < n; i++)
{
int l = read(), k = read();
link(k, l);
indegree[l]++;
}
for(int i = 1; i <= n; i++) if(indegree[i] == 1)
{
root = i; break;
}
printf("%d\n", std::max(solve(root, 0), solve(root, 1)));
return 0;
}

浙公网安备 33010602011771号