华电北风吹
天津大学认知计算与应用重点实验室
日期:2015/9/15
poj上一道与动态规划特别像的题目(http://poj.org/problem?id=2342),一个公司要出席一些人员,每个人对应一个活跃度,要求是不能存在直属关系,活跃度最大。参考了别人的博客,很多人说这个是树形动态规划,我个人感觉应该划分到分治法里面(不存在重叠子问题)。
下面是我修改后的代码,采用递归的思路。例如计算根节点的最大活跃度,需要判断根节点的每一个子节点,根节点出席的话就把子节点不出席时候的活跃度相加,如果根节点不出席,就把所有根节点出席和不出席中活跃度最大的加起来,依次递归。其中,leader保存每个节点的直属leader,dp[i][0/1] 保存当前节点子树出席和不出席的活跃度。
C++ code:
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
#define maxn 100
int n;
int dp[maxn][2], leader[maxn]; //dp[i][0]0表示不去,dp[i][1]1表示去了
void tree_dp(int node)
{
int i;
for (i = 1; i <= n; i++)
{
if (leader[i] == node) //i为下属
{
tree_dp(i); //递归调用孩子结点,从叶子结点开始dp
dp[node][1] += dp[i][0]; //上司来,下属不来
dp[node][0] += max(dp[i][1], dp[i][0]); //上司不来,下属来、不来
}
}
}
int main()
{
ifstream in("C:\\Users\\zhengyi\\Desktop\\ConsoleApplication1\\input.txt");
cin.rdbuf(in.rdbuf());
int i;
int f, c, root;
while (cin>>n)
{
memset(dp, 0, sizeof(dp));
memset(leader, 0, sizeof(leader));
for (i = 1; i <= n; i++)
{
cin>>dp[i][1];
}
while (cin>>c>>f, c || f)
{
leader[c] = f;
root = f;
}
while (leader[root]) //查找父结点
root = leader[root];
tree_dp(root);
int imax = max(dp[root][0], dp[root][1]);
printf("%d\n", imax);
}
system("pause");
return 0;
}
python code:
file=open('datahdu1520.txt','r')
line=file.readline()
N=int(line.strip('\n'))
activity=[int(file.readline().strip('\n')) for i in range(N)]
leader=[i for i in range(N)]
root=0
while True:
line=file.readline()
if line=="0 0":
break
line=line.split()
leader[int(line[0])-1]=int(line[1])-1
root=int(line[1])-1
dp=[[0 for col in range(2)] for row in range(N)]
def func(person):
dp[person][0]=0
dp[person][1]=activity[person]
for i in range(N):
if leader[i]==person and i!=person:
func(i)
dp[person][0]=dp[person][0]+max(dp[i])
dp[person][1]=dp[person][1]+dp[i][0]
while leader[root]!=root:
root=leader[root]
func(root)
print(max(dp[root]))