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])
同样的题目在hdu也有:
HDU 1520 Anniversary party
题目是说有N个人参加party,每个人有一个rating值(可以理解为权值)和一个up(上司的编号),为了保证party的趣味性,每一个人不可以和他的直接上司都参加,问最后的rating和最大
这是一个典型的树形DP,DP[u][0]表示u不参加那他的这棵子树上的最大权值,DP[u][1]表示u参加时的这棵树上的最大权值,
每个U节点有两种选择 参加party时的该他的树的权值(dp[u][1]),不去参加party该树的权值(dp[u][0]);
当他(u)不去时,他本身的权值(dp[u][0])就等于 他所有后面节点(儿子节点,后继节点)最大的权值(他儿子节点有两种情况,去或不去,所以是求最大值之和)dp[u][0] += max(dp[v][1], dp[v][0]);
当(u)去时,它本身的权值dp[u][1])只能加上他所有后面节点(儿子节点,后继节点)不去时的权值。dp[u][1] += dp[v][0];
v是从u读出来的 后面节点(儿子节点,后继节点)。
代码链接 https://blog.csdn.net/readlnh/article/details/52226453
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
#include
#include
#include
using namespace std;
const int maxn=6000+10;
vectorG[maxn];
int dp[maxn][2],n,u,v,f[maxn];
void dfs(int root)
{
for(int i=0;i
2、POJ-1463
现在要在一棵树上布置士兵,每个士兵在结点上,每个士兵可以守护其结点直接相连的全部边,问最少需要布置多少个士兵。
还是简单树形dp,状态转移方程好写。
dp[i][0]表示这个点不选(说明子结点全部选),因为只有子结点全部选,才能确保这个点到子结点的全部边都有士兵守卫。
dp[i][1]表示这个点选,那么子结点就是+min(选/不选),然后对根结点一样是判断0与1的大小即可
#include
#include
#include
using namespace std;
const int maxn=1500+10;
int n,f[maxn],v,num,u,dp[maxn][2];
vectorG[maxn];
void dfs(int root)
{
for(int i=0;i
3、POj-2378
给一一颗树,问删除哪些结点可以使得剩下的子图每一个连通分支的节点数<=总/2。
那么dp[i]表示这棵子树的下面的(包括其)的总结点数
如果一棵树其全部子树<=总/2,且总-其全部子树结点和-1<=总/2,那么这个结点就合适,用个数组来储存,最后排序即可
这题需要注意的是,上面两个题是有向图的保存方式,这题属于无向图的保存方式,可以从任意一点出发,无需找到根节点
具体看代码:
#include
#include
#include
#include
using namespace std;
const int maxn=1e4+10;
vectorG[maxn],que;
int n,v,u;
int dfs(int root,int fa)
{
// if(G[root].size()==1&&G[root][0]==fa) return 1;//可有可无,判断叶子节点
int mx=0,sum=1,u;
for(int i=0;i
4、ZOJ-3201***(agin)
给一棵树,问这棵树大小为k的子树最大的权值和是多少。
这题稍微有点难度,dp[i][j]表示i结点长度为j(包括其)的最大权值是多少。
然后对于每个其子结点就进行背包dp,判断这个结点对于长度为l的权值是否应该要(这里需要注意的就是一个结点不能要多次,所以应该从大到小dp(类似背包),而且要一个数组储存最初状态,比如这个根结点只有长为1的链,但是这个子结点长为3,计算到2的时候这个根结点已经有长度为3的结点了,再计算子结点为3的时候,发现根结点有3长度的结点,就会出现这个根结点存在长度为6的链,显然这是错误的)。
这个题属于在树上的dp,我也是理解很久才懂,有点难度,跟01背包相似又有区别
两个代码:
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
#define mst(s, t) memset(s, t, sizeof(s))
const int INF = 0x3f3f3f3f;
const int maxn = 110;
vector G[maxn];
int dp[maxn][maxn]; //dp[i][j]:node[i]结点数为j的子树的最大权值
int k, ans, cnt[maxn], weight[maxn];
int dfs(int node, int father)
{
cnt[node] = 1;
for(int i=0; i= 1; j--)
{
for(int t = 0; t
#include
using namespace std;
int d[105][105],a[105],n,k,ans;
vectorG[105];
void dfs(int u,int fa)
{
d[u][1]=a[u];
for(int i=0;i0;j--)
for(int p=1;p+j<=k;p++)
d[u][j+p]=max(d[u][j+p],d[u][j]+d[v][p]);
}
ans=max(ans,d[u][k]);
}
int main()
{
int u,v;
while(~scanf("%d%d",&n,&k))
{
for(int i=0;i
5 - Cell Phone Network
题意:给n[1,10000]个点,n-1条边,树形结构,从n个点中取尽量少的点构成一个集合,使剩下所有点都能与这个集合中的部分点相连。
(这个概念叫最小支配集),第二题应该就是最小点覆盖了
这个题我不太会,待补(有点难)
F - Computer(待补,有难度)
题意:一棵边带权值的树,求每个点在树上的最远距离。