树形DP和状压DP
P1352 没有上司的舞会
作为一道经典例题,几乎学树形 \(DP\) 就得先做它。
设 \(f[i][j]\) ,当 \(j\) 为 \(0\) 时表示第 \(i\) 个人不来,当 \(j\) 为 \(1\) 时表示第 \(i\) 个人来,所以状态转移方程为:
\]
\]
#include<bits/stdc++.h>
using namespace std;
int dp[200020][2];
int n;
int h[200003];
struct node{
int to,nxt;
}z[200003];
int cnt;
void add(int a,int b){
z[++cnt].to=b;
z[cnt].nxt=h[a];
h[a]=cnt;
}
int a[200003];
void dfs(int now,int fa){
dp[now][0]=0;
dp[now][1]=a[now];
for(int i=h[now];i;i=z[i].nxt){
int y=z[i].to;
if(y==fa) continue;
else{
dfs(y,now);
dp[now][0]+=max(dp[y][0],dp[y][1]);
dp[now][1]+=dp[y][0];
}
}
}
int in[200003];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++) {
int k,l;
scanf("%d%d",&l,&k);
add(k,l);
in[l]++;
}
int boss;
for(int i=1;i<=n;i++) if(!in[i]){ boss=i;break; }
dfs(boss,0);
cout<<max(dp[boss][1],dp[boss][0]);
}
P2014 [CTSC1997] 选课
其实就是一个 \(01\) 背包。
设 \(f[i][j]\) 表示以 \(i\) 为根的子树中选了 \(j\) 个点的最大价值。
对于点 \(x\) 遍历自己的儿子们,然后不断与自己合并。
#include<bits/stdc++.h>
using namespace std;
struct node{
int nxt,to;
}z[305];
int n,m,cnt;
int h[305];
int dp[305][304];
void add(int u,int v){
cnt++;
z[cnt].nxt=h[u];
z[cnt].to=v;
h[u]=cnt;
}
void dfs(int x){
for(int i=h[x];i;i=z[i].nxt){
int y=z[i].to;
dfs(y);
for(int j=m;j>=1;j--){
for(int k=0;k<j;k++){
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]);
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&dp[i][1]);
add(a,i);
}
m++;
dfs(0);
printf("%d",dp[0][m]);
}
P3478 [POI2008] STA-Station
我们可以先从第 \(1\) 个节点搜,预处理出当以 \(1\) 为根的深度和还有每个点的子树大小。
然后再来一遍 \(DFS\) 我们发现,当以 \(x\) 为根时,对于以 \(x\) 的父亲为根时,自己的子树的深度都会减 \(1\),而其他的点的深度都会加 \(1\),所以就得到了状态转移方程。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
struct node{
int to,nxt;
}z[2000004];
int h[1000004];
int cnt;
void add(int x,int y){
z[++cnt].to=y;
z[cnt].nxt=h[x];
h[x]=cnt;
}
int dep[1000004];
int siz[1000004];
int sum_dep[1000005];
void dfs(int x,int fa){
siz[x]=1;
dep[x]=dep[fa]+1;
for(int i=h[x];i;i=z[i].nxt ){
int y=z[i].to;
if(y==fa) continue;
else{
dfs(y,x);
siz[x]+=siz[y];
}
}
}
int f[1000004];
void DFS(int x,int fa){
for(int i=h[x];i;i=z[i].nxt){
int y=z[i].to;
if(y==fa) continue;
else{
f[y]=f[x]-1ll*2*siz[y]+n;
DFS(y,x);
}
}
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<n;i++){
int u,v;
scanf("%lld%lld",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
int t;
int maxx=0;
for(int i=1;i<=n;i++) f[1]+=dep[i];
DFS(1,0);
for(int i=1;i<=n;i++){
//maxx=max(maxx,f[i]);
if(maxx<f[i]){
maxx=f[i];
t=i;
}
}
cout<<t<<endl;
}
P2607 [ZJOI2008] 骑士
这是一颗基环树,所以我们肯定不能上来就做。
我们可以先找到环,然后跑两次 \(DFS\) 就好了
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int f[N][2];
int val[N];
int n;
struct node{
int to,nxt;
}z[2*N];
int cnt;
int h[N];
int F[N];
int vis[N];
void add(int x,int y){
z[++cnt].to=y;
z[cnt].nxt=h[x];
h[x]=cnt;
}
int root;
void dp(int x){
f[x][0]=0;
f[x][1]=val[x];
vis[x]=1;
for(int i=h[x];i;i=z[i].nxt){
int y=z[i].to;
if(y!=root){
dp(y);
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
}
else{
f[y][1]=-1e9;
}
}
}
int ans;
void Find(int x){
root=x;
vis[x]=1;
while(!vis[F[root]]){
root=F[root];
vis[root]=1;
}
dp(root);
int t=max(f[root][1],f[root][0]);
vis[root]=1;
root=F[root];
dp(root);
ans+=max(t,max(f[root][1],f[root][0]));
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
int fa;
cin>>val[i]>>fa;
F[i]=fa;
add(fa,i);
}
for(int i=1;i<=n;i++){
if(!vis[i]){
Find(i);
}
}
cout<<ans;
}
P1896 [SCOI2005] 互不侵犯
一道很普通的状压 DP。
首先预处理出所有状态(即代码中的 \(dfs\) )。
然后定义 \(f[i][j][k]\) 表示d第 \(i\) 行的状态为 \(j\),一共选了 \(k\) 个。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,K;
int sum_s[20090];
int f[10][120][100];
int cnt;
int s[20004];
void dfs(int x,int sum,int y){
if(y>=n){
s[++cnt]=x;
sum_s[cnt]=sum;
return ;
}
dfs(x,sum,y+1);
dfs(x+(1<<y),sum+1,y+2); //因为两个King不能相邻
}
signed main(){
cin>>n>>K;
dfs(0,0,0);
for(int i=1;i<=cnt;i++) f[1][i][sum_s[i]]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=cnt;j++){
for(int k=1;k<=cnt;k++){
if(s[j]&s[k]) continue;
if((s[j]<<1)&s[k]) continue;
if(s[j]&(s[k]<<1)) continue;
for(int p=K;p>=sum_s[j];p--){
f[i][j][p]+=f[i-1][k][p-sum_s[j]];
}
}
}
}
int ans=0;
for(int i=1;i<=cnt;i++) ans+=f[n][i][K];
cout<<ans;
}
树形DP和状压DP的更多相关文章
- 树形DP和状压DP和背包DP
树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...
- dp乱写1:状态压缩dp(状压dp)炮兵阵地
https://www.luogu.org/problem/show?pid=2704 题意: 炮兵在地图上的摆放位子只能在平地('P') 炮兵可以攻击上下左右各两格的格子: 而高原('H')上炮兵能 ...
- poj2411 Mondriaan's Dream (轮廓线dp、状压dp)
Mondriaan's Dream Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 17203 Accepted: 991 ...
- BZOJ 4042 Luogu P4757 [CERC2014]Parades (树形DP、状压DP)
题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4042 (Luogu) https://www.luogu.org/prob ...
- dp,状压dp等 一些总结
也就作业几题而已,分析一下提醒 最重要的就是,记住,没用的状态无论怎么转移最后都会是没用的状态,所以每次转移以后的有值的状态都是有用的状态. 几种思考方向: 第一种:枚举当前的状态,转移成另外一个状态 ...
- hoj 2662 经典状压dp // MyFirst 状压dp
题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2662 1.引言:用dp解决一个问题的时候很重要的一环就是状态的表示,一般来说,一个数组即可保存状态. ...
- 【BZOJ3925】地震后的幻想乡(期望概率DP,状压DP)
题意:给定一张点数不超过10的无向连通图,每条边有一个[0,1]之间的随机权值,求最小生成树上最大边的期望值 提示:对于n个[0,1]之间的随机变量x1,x2,...,xn,第k小的那个的期望值是k/ ...
- hdu4352 XHXJ's LIS[数位DP套状压DP+LIS$O(nlogn)$]
统计$[L,R]$内LIS长度为$k$的数的个数,$Q \le 10000,L,R < 2^{63}-1,k \le 10$. 首先肯定是数位DP.然后考虑怎么做这个dp.如果把$k$记录到状态 ...
- 【dp】状压dp
二进制的力量 状态压缩DP 愤怒的小鸟 第一次接触状态压缩DP是在NOIP2016的愤怒的小鸟,当时菜得连题目都没看懂,不过现在回过头来看还是挺简单的,那么我们再来看看这道题吧. 题意&数据范 ...
- poj3254 Corn Fields (状压DP)
http://poj.org/problem?id=3254 Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissio ...
随机推荐
- helm部署redis集群
Redis 集群部署流程 前提:K8s+helm安装完成 1. 安装 NFS 服务器 1.1 安装 NFS 工具包 在 NFS 服务器上安装 nfs-utils 包: sudo yum install ...
- 机器人技术的突破让OpenAI过时了
机器人技术的突破让OpenAI过时了 Ignacio de Gregorio 最近,Figure AI,一家价值数十亿美元的AI机器人公司,宣布取消与OpenAI的合作伙伴关系,这一举动看起来是相当大 ...
- xxe学习笔记
什么是xxe XXE(XML External Entity Injection)全称为XML外部实体注入,由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的.例如PHP中的simp ...
- MongoDB 简单介绍
MongoDB介绍 疑问 解答 什么是 MongoDB 一个以 JSON 为数据模型的文档数据库 为什么叫文档数据库? 文档来自于 "JSON Document",并非我们一般理解 ...
- 阅读IDEA生成的equals方法--java进阶day05
1.IDEA生成的equals方法 虽然我们之前写了equals方法,但IDEA中可以快速生成equals方法,因此,我们要能看懂IDEA生成的equals方法 1.if(this==o) 2.if( ...
- Windows 延缓写入失败及解决方法
场景重现 某天系统弹出警告:某盘符延缓写入失败 解决办法 [Win + R]或手搓打开cmd.exe,键入chkdsk: 然后等待校检完成. 完成之后到警告提示对应的盘符下进行查错并修复 然后等待检查 ...
- study Python3【3】的函数
Python的函数定义简单,但灵活度非常大.功能强大意味复杂.为了复习,把廖雪峰老师的该课程做个回顾. 参数有:必选参数.默认参数.可变参数.关键字参数.命名关键字参数. 计算x的n次方函数: def ...
- JBoltAI 与 AIGS 的深度融合:重构企业数智化未来
在企业数智化转型浪潮中,JBoltAI 凭借其独特的 AIGS(AI Generate Service)解决方案,正成为连接大模型能力与企业实际需求的桥梁.其核心价值在于通过技术框架的重构,将 AI ...
- 0x01 基础算法
目录 基础算法 排序 快速排序 归并排序 二分 整数二分 浮点数二分 高精度 输入输出 高精度加法 高精度减法 高精度乘法 高精度除法 前缀和 差分 双指针算法 位运算 离散化 区间合并 基础算法 排 ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Health Service Kit
1.问题描述: 按照官方文档调用healthStore API申请用户授权:有拉起授权弹窗,但是无回调,检查权限接口也无回调. 解决方案: 1.接口调用前,需先使用init方法进行初始化,没有回调的问 ...