树形DP题目。。。转载
http://acm.hdu.edu.cn/showproblem.php?pid=2196√
向下搜一遍,向上搜一遍
http://acm.hdu.edu.cn/showproblem.php?pid=1561 √
对每一个节点进行一次背包,好题啊,两个DP树形和背包结合的
http://acm.hdu.edu.cn/showproblem.php?pid=1011√
这道是当年省赛的压轴题,但是感觉和上一道差不多,一样的难度,唯一不同的就是这个是无向图(我由于思维惯性拿来当单向图作,纠结了好久。。。)
树形+背包+临街表
下边是从天涯空间里找出来的练习
http://acm.pku.edu.cn/JudgeOnline/problem?id=3345
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3201
和上边几个题一样树形dp+背包。在理解上还是不熟练啊。
dp[i][j+k] = max(dp[i][j+k],dp[i][j] + dp[u][k]) u是i的子节点
注意从0开始dfs
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#define maxn 107
using namespace std;
vector<int>g[maxn];
bool visit[maxn];
int dp[maxn][maxn],k,val[maxn];
void dfs(int rpos)
{
int i,j;
visit[rpos] = true;
dp[rpos][1] = val[rpos];
int size = g[rpos].size();
for (i = 0; i < size; ++i)
{
int u = g[rpos][i];
if(!visit[u])
{
dfs(u);
for (j = k; j >= 1; --j)//j要从最大之开始,保证后边的dp[rpos][j]从未加过子节点的值
{
for (int ki = 1; ki+j <= k; ++ki)
if(dp[u][ki])
dp[rpos][j+ki] = max(dp[rpos][j+ki],dp[rpos][j] + dp[u][ki]);
}
}
}
}
int main()
{
int n,i,x,y;
while (cin>>n>>k)
{
for (i = 0; i < n; ++i)
{
g[i].clear();
scanf("%d",&val[i]);
}
for ( i = 0; i < n-1; ++i)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
memset(dp,0,sizeof(dp));
memset(visit,false,sizeof(visit));
dfs(0);
int ans =0 ;
for (i = 0; i < n; ++i)
{
ans = max(ans,dp[i][k]);
}
printf("%d\n",ans);
}
return 0;
}
http://acm.pku.edu.cn/JudgeOnline/problem?id=3107
求一棵树去掉一点变成森林之后的最大分支量,然后输出去掉后使最大分支量最小的点(可能有多个)。
思路:最大分支量= max(要去掉的节点子树所拥有的总结点数最大值,总数 - 要去掉的节点所拥有的总结点数 )
num[i]表示以该节点为根,它所拥有的节点总数
这道题用stl的vector会tle,于是我就转换成静态邻接表结果还是tle,最后用了边表才过。这题二了。。中间把ma定义成了全局变量,检查了好几个小时才查到。悲催啊。。。。哭,,
#include <cstdio>
#include <cstring>
#include <iostream>
#define maxn 50007
#define inf 0x7fffffff
using namespace std;
struct node
{
int v;
int next;
}g[maxn*2];
bool visit[maxn];
int num[maxn],ans[maxn],head[maxn];
int n,mm,t;
void add(int u,int v)
{
g[t].v = v;
g[t].next = head[u];
head[u] = t++;
}
void dfs(int rpos)
{
num[rpos] = 1;
visit[rpos] = true;
int ma = -1;//这里要局部,不能全局
for (int i = head[rpos]; i != 0; i = g[i].next)
{
int u = g[i].v;
if (visit[u]) continue;
dfs(u);
num[rpos] += num[u];
ma = max(ma,num[u]);
}
ma = max(ma,n - num[rpos]);
ans[rpos] = ma;
mm = min(mm,ma);
}
int main()
{
int i,x,y;
while (~scanf("%d",&n))
{
t = 1;
for (i = 0; i < maxn; ++i)
{
num[i] = ans[i] = head[i] = 0;
visit[i] =false;
}
memset(g,0,sizeof(g));
for (i = 1; i < n; ++i)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
mm = inf;
dfs(1);
int flag = 0;
for (i = 1; i <= n; ++i)
{
if (mm == ans[i])
{
if (!flag)
{
printf("%d",i);
flag = 1;
}
else
{
printf(" %d",i);
}
}
}
printf("\n");
}
}
http://acm.pku.edu.cn/JudgeOnline/problem?id=1655
和pku 3107一样,只是改一下输出就A了。可是今天我又二了。。pe了好几次。。代码同上
http://acm.pku.edu.cn/JudgeOnline/problem?id=2378
http://acm.pku.edu.cn/JudgeOnline/problem?id=3140
http://acm.hdu.edu.cn/showproblem.php?pid=2242
http://acm.timus.ru/problem.aspx?space=1&num=1018
http://acm.pku.edu.cn/JudgeOnline/problem?id=1947
http://acm.pku.edu.cn/JudgeOnline/problem?id=2057
http://acm.pku.edu.cn/JudgeOnline/problem?id=2486
http://acm.pku.edu.cn/JudgeOnline/problem?id=1848
http://acm.pku.edu.cn/JudgeOnline/problem?id=2152
http://acm.hdu.edu.cn/showproblem.php?pid=1520√