1、POJ-2342
在一个公司中,每个职员有一个快乐值ai,现在要开一个party,邀请了一个员工就不可能邀请其直属上司,同理邀请了一个人就不可以邀请其的直属员工,
问如何使得这个快乐值达到最大。
显然简单树形dp,对每个结点dp[i][0]表示不邀请这个员工,其子树达到的最大快乐值,dp[i][1]表示邀请i员工其子树达到的最大值。
dp[i][0]=(i的全部员工的max(dp[u][1],dp[u][0)相加,也就是其子员工来或不来的最大快乐值。
dp[i][1]=(i的全部员工的dp[u][0相加,也就是其子员工都不能不来的最大快乐值。
从大boss开始dp,最终结果就是max(dp[root][0],dp[root][1])
先直接搜索到最底层,然后一层一层动态规划,可以说有点像数塔。
dp[i][1],dp[i][0]代表取这个节点和不取这个节点,所以。
dp[i][1]+=dp[v][0] v是的子节点
dp[i][0]+=max(dp[v][1],dp[v][0])
初始的时候将最后一层叶子节点dp[i][1]赋值为相应值即可。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node{
int v,nxt;
}e[12000];
int dp[6005][2],father[6005];
int num,head[6005];
int max(int a,int b){
return a>b?a:b;
}
void add(int a,int b){
e[num].v=b;e[num].nxt=head[a];head[a]=num++;
}
void dfs(int n){
int i;
for(i=head[n];i!=-1;i=e[i].nxt){
int v=e[i].v;
if(father[v]==n){
dfs(v);
dp[n][1]+=dp[v][0];
dp[n][0]+=max(dp[v][1],dp[v][0]);
}
}
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF){
memset(dp,0,sizeof(dp));
memset(head,-1,sizeof(head));
memset(father,0,sizeof(father));
num=0;
int i;
for(i=1;i<=t;i++)
scanf("%d",&dp[i][1]);
int root=1;
int a,b;
while(scanf("%d%d",&a,&b),a||b){
father[a]=b;
add(b,a);
if(father[b]==0) root=b;
}
dfs(root);
printf("%d\n",dp[root][1]>dp[root][0]?dp[root][1]:dp[root][0]);
}
return 0;
}
题意:
一城堡的所有的道路形成一个n个节点的树,如果在一个节点上放上一个士兵,那么和这个节点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵。
分析:
典型树形动态规划:树的最小点覆盖
•第一步:确定状态
•f[x][1]以x为根的子树在x上放置的士兵的最少所需的士兵数目
•f[x][0]以x为根的子树x上不放置的士兵的最少所需的士兵数目
•第二步:确定状态转移方程
•f[x][1] =1 + Σ min(f[son][0],f[son][1])
•若x上放置的士兵,它的儿子们可放可不放,取最小值
•f[x][0] = Σ f[son][1]
•若x上不放置的士兵,它的儿子们都必须放!
•结果为min(f[root][0], f[root][1]),取根节点放与不放的最小值
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn=1600;
int n;
int father[maxn];
vector<int>G[maxn];//存储有向图
int dp[2][maxn];
void dfs(int x)//无需指定x的根节点
{
for(int i=0;i<G[x].size();i++)
{
int son=G[x][i];
dfs(son);
dp[0][x]+=dp[1][son];//这一点不放,则儿子必须放
dp[1][x]+=min(dp[0][son],dp[1][son]);//这一点放
}
}
int main()
{
while(scanf("%d",&n)!=EOF){
memset(father,-1,sizeof(father));
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
dp[1][i]=1;
G[i].clear();
}
for(int i=0;i<n;i++)
{
int id,num,kid;
scanf("%d:(%d)",&id,&num);
for(int j=0;j<num;j++)
{
scanf("%d",&kid);
G[id].push_back(kid);
father[kid]=0;
}
}
int root=1;
for(int i=0;i<n;i++)
{
if(father[i]==-1)
{
root=i;break;
}
}
//printf("R:%d\n",root);
dfs(root);
printf("%d\n",min(dp[1][root],dp[0][root]) );
}
return 0;
}