树形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 ...
随机推荐
- FastAPI极速入门:15分钟搭建你的首个智能API(附自动文档生成)🚀
title: FastAPI极速入门:15分钟搭建你的首个智能API(附自动文档生成) date: 2025/3/1 updated: 2025/3/1 author: cmdragon excerp ...
- 记录:tinyrenderer
Bresenham's line drawing(布雷森汉姆算法) 进行games101的光栅化作业时,对其渲染原理仍不甚了解,找到tinyrenderer软光栅项目.在此记录下试错的过程. 作者在最 ...
- 【目标检测】二、Fast R-CNN与SVD
1.流程 (1) 空间金字塔池化(spatial pyramid pooling,SPP) 原理: (2)Fast-RCNN 2.数学概念 这么多个全连接层,必然存在计算的性能问题,让数学家们蠢蠢欲动 ...
- VNCTF2025_Crypto
VNCTF2025_Crypto Simple prediction task.py from random import shuffle from Crypto.Util.number import ...
- [Qt 基础-02] QToolButton
QToolButton 文章目录 QToolButton 简介 1. arrowType 2. autoRaise 3. popupMode 4. toolButtonStyle 注意 信号的连接 样 ...
- go 语言中的占位符详解
在 Go 语言的 fmt 包中,占位符用于格式化输出,允许在输出时插入变量的值.以下是一些常用的占位符及其用法: 通用占位符: %v:按照值的默认格式输出. %+v:输出结构体时,会添加字段名. %# ...
- 【Java】可比较泛型建数组传递报强转类型错误解决方案
问题 可比较泛型怎么新建数组? 自己写基于AVL树的散列表时,在自动扩容的时候需要遍历AVL树的Key,所以需要AVL树提供一个方法返回一个Key数组以遍历,初始实现如下: /** * 用于辅助遍历K ...
- 康谋技术 |高效同步与处理:ADTF流服务在自动驾驶数采中的应用
随着自动驾驶技术的发展,车辆的智能化程度不断提高,这体现了车辆感知,决策以及执行的能力.在算法开发和迭代过程中,提高测试和开发效率,关键在于多传感器数据的高质量采集,确保数据的同步性.完整性和一致性. ...
- GPFS并行文件系统部署实践
环境 ubuntu22.04 试用版下载链接 https://www.ibm.com/cn-zh/products/storage-scale 我的版本:Storage_Scale_Developer ...
- 一步到位js/javascript对象和querystring查询字符串互转(get/url参数)
当然,这个问题又很多解决方式,这里说一种最简洁的方式: 对象转querystring查询字符串(get/url参数) 我看网上的方法都比较繁琐,其实可以直接使用js的URLSearchParams对象 ...