【DP】树形DP 记忆化搜索

DP中的树形DP,解决方法往往是记忆化搜索。显然,树上递推是很困难的。当然做得时候还是得把状态定义和转移方程写出来:dp[u][1/0]表示以u为根节点的树 涂(1) 或 不涂(0) 颜色的最少方案数。树上DP有两个经典问法:一条边两端至少有个一个端点涂色,问整个tree最少涂色次数;还有一种忘了。。。此题是前种问法。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=2000;
int first[maxn],tot;
int dp[maxn][3];
int n,in[maxn];
struct Edge
{
    int from,to,next;
}E[maxn];
void init()
{
    memset(first,-1,sizeof(first));
    tot=0;
    memset(dp,-1,sizeof(dp));
    memset(in,0,sizeof(in));
}
void addedge(int u,int v)
{
    E[tot].from=u;
    E[tot].to=v;
    E[tot].next=first[u];
    first[u]=tot++;
}
int dfs(int u,bool flag)
{
    if(flag){ if(dp[u][1]!=-1) return dp[u][1];}
    else    { if(dp[u][0]!=-1) return dp[u][0];}
    dp[u][1]=1;
    dp[u][0]=0;
    for(int e=first[u];e!=-1;e=E[e].next)
    {
        int v=E[e].to;
        dp[u][1]+=min(dfs(v,true),dfs(v,false));
        dp[u][0]+=dfs(v,true);
    }
    if(flag) return dp[u][1];
    return dp[u][0];
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        int node,num,a;
        for(int i=0; i<n; i++)
        {
            scanf("%d:(%d)",&node,&num);
            for(int i=0; i<num; i++)
            {
                   scanf("%d",&a);
                in[a]++;
                addedge(node,a);
            }
        }
        int root;
        for(int i=0;i<n;i++)
            if(in[i]==0){root=i;break;}
//        cout<<"root "<<root<<endl;

        printf("%d\n",min(dfs(root,true),dfs(root,false)));
//        for(int i=0;i<n;i++)
//            cout<<dp[i][0]<<" "<<dp[i][1]<<endl;
    }
}

【DP】树形DP 记忆化搜索

时间: 2024-12-26 15:51:53

【DP】树形DP 记忆化搜索的相关文章

hdu4753 状态压缩dp博弈(记忆化搜索写法)

http://acm.hdu.edu.cn/showproblem.php?pid=4753 Problem Description There is a 3 by 3 grid and each vertex is assigned a number. It looks like JiuGongGe, but they are different, for we are not going to fill the cell but the edge. For instance, adding

NYOJ16|嵌套矩形|DP|DAG模型|记忆化搜索

矩形嵌套 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度).例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中.你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内. 输入 第一行是一个正正数N(0<N<10),表示测试数据组数,每组测

ACM学习历程—ZOJ3471 Most Powerful(dp &amp;&amp; 状态压缩 &amp;&amp; 记忆化搜索 &amp;&amp; 位运算)

Description Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappears and a lot of power is produced. Researchers know the way

poj 1609 Tiling Up Blocks dp入门之记忆化搜索

题意: 给n个二元组(a,b),要在其中找最长的序列,使得对序列中的任意i<j,有ai<=aj且bi<=bj. 分析: 设dp[a][b]代表以(a,b)结尾的最长序列长度,记忆化搜索即可. 代码: //poj 1609 //sep9 #include <iostream> using namespace std; const int max_p=128; int n; int num[max_p][max_p]; int dp[max_p][max_p]; int sear

poj1191 棋盘分割【区间DP】【记忆化搜索】

棋盘分割 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16263   Accepted: 5812 Description 将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘.(每次切割都只能沿着棋盘格子的边进行) 原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和.现在需要把棋盘按上述规

换根dp+暴力+预处理+记忆化搜索——cf1292C好题!

/** 给定一棵树,要求给树边赋值[0,n-2],每个值只能使用一次 S = mex(u,v), mex(u,v)是u-v路径上没有出现过的编号最小的值 问使得S最大的赋值方式 由于很难直接统计答案,所以考虑统计每条边的贡献 包含(0)路径的贡献tot1是其左右子树size的乘积 包含(0,1)的路径的贡献tot2是其左右子树的size乘积 ...依次类推 显然:只包含(1,2)这样的路径是没有贡献的 那么原问题转化为如何分配[0,n-2],使得最后的乘积和最大 dp[u][v]表示路径(u,v

机房测试13:dp专题(单调队列+树形背包+记忆化搜索)

T1: 很容易写出dp式子:定义dp[i][j]为现在是第i个烟火,位置在j,然后就可以枚举上一个时间的位置k转移过来.(j-(t[i]-t[i-1])*d <= k <=j+(t[i]-t[i-1])*d) 这样是n*n*m的,考虑优化. 固定一个边界:j-(t[i]-t[i-1])*d<=k 可以发现,当j变大,k的范围会变小,于是就可以维护一个单调递减的队列,队头就是答案. 而另外一个边界同理,只需要反过来做一遍就可以了. 注意: 1. 开滚动数组!!否则爆空间 2.不需要初始化负

【区间dp】【记忆化搜索】UVALive - 3516 - Exploring Pyramids

f(i,j)=sum(f(i+1,k-1)*f(k,j) | i+2<=k<=j,Si=Sk=Sj). f(i+1,k-1)是划分出第一颗子树,f(k,j)是划分出剩下的子树. #include<cstdio> #include<cstring> using namespace std; typedef long long ll; #define MOD 1000000000ll char s[310]; ll f[310][310]; int n; ll dp(int

hdu 3555 数位dp水题 记忆化搜索做法

#include<iostream> #include<cstring> #include<cstdio> using namespace std ; const int maxn = 20; __int64 dp[maxn][3] ;//dp[i][flag] ,flag = 2,表示已经有49,flag == 1,表示没有49,这一位是4, int bit[maxn] ;    //flag == 0, 什么都没有 __int64 dfs(int pos , int

UVa 10651 Pebble Solitaire (DP 卵石游戏 记忆化搜索)

 题意  给你一个长度为12的字符串  由字符'-'和字符'o'组成  其中"-oo"和"oo-"分别可以通过一次转换变为"o--"和"--o"  可以发现每次转换o都少了一个  只需求出给你的字符串做多能转换多少次就行了 令d[s]表示字符串s最多可以转换的次数  若s可以通过一次转换变为字符串t  有d[s]=max(d[s],d[t]+1) #include<iostream> #include<s