首页 > 其他分享 >20230703-动态规划DP 1

20230703-动态规划DP 1

时间:2023-07-19 22:56:06浏览次数:42  
标签:head ch 20230703 int 括号 2n 动态 DP

20230703

热身

题目

求长度为n的合法括号序列有多少个,对\(10^9+7\)取模。
\(n\)为偶数,\(n\le 10^6\)。

Solution

可以维护一个栈
遇到一个左括号就加入栈
而遇到右括号时就取栈顶的左括号与它配对出栈
一个合法序列需要保证:

  1. 最后栈为空,即所有的左括号都和有括号配对了
  2. 中间不能出现遇到一个右括号时栈里没有左括号了

这样我们可以把栈里的括号数量转化到平面直角坐标系上面
这样可以得到一条折线
而这条折线就对应一个括号序列
它是合法的当且仅当:

  1. 没有一部分跑到了x轴下方
  2. 最后折线结束在(n,0)的位置

image
图中这个序列是不合法的,因为红色圈起来的地方在x轴下方了

我们考虑将这样的折线转化成横平竖直的变化
考虑再建立一个平面直角坐标系
把原来的也放进去
我们把x轴逆时针旋转45度
得到了一条直线\(l1:y=x\)
那么我们每一次的变化可以转化为从原点向前走和向上走
但是不能超过这条直线\(l1:y=x\)
最终走到\((n,n)\)
由于不超过很难去判断
我们可以在设一条直线\(l2:y=x+1\)
这样走的路径不碰到\(l2\)即可

而对于每一个碰到\(l2\)的折线
我们考虑把它沿着\(l2\)翻折
这样起点\((0,0)\)就变到了\((-1,1)\)
在\((0,0) \to (n,n)\)的方案中
有部分合法有部分不合法
而那部分不合法的我们把它翻折过去
成了\((-1,1) \to (n,n)\)的方案
这样方案数就是
\((0,0) \to (n,n)的方案数 - (-1,1) \to (n,n)的方案数\)

再来考虑怎么计算
从\((0,0) \to (n,n)\)我们一共会走\(2n\)步
而每一步我们可以选择向上和向右之间的一种
而一共需要\(n\)步向上和\(n\)步向右
方案数相当于在\(2n\)个东西中选\(n\)个向上走的方案数
也就是\(C_{2n}^{n}\)

同理
从\((-1,1) \to (n,n)\)的方案数就是
\(C_{2n}^{n-1}\)

这样答案就为\(C_{2n}^{n}-C_{2n}^{n-1}\)
这个数也就是卡特兰数

树形DP

CF581F Zublicanes and Mumocrates

题目大意

传送门
给出一棵n个点的树,保证它有偶数个叶子节点,请对该树的所有节点进行黑白染色,使得黑色与白色的叶子节点数相等,且直接连接两个异色点的边数最少。
\(n \le 5000\)

Solution

很明显的树形DP
考虑\(f[u][i][0/1]\)表示在节点\(u\)的子树中
叶子结点为黑色的有\(i\)个,当前节点颜色为黑色1白色0的最小边数
考虑依次枚举\(u\)的每一个儿子\(v\)
那么我们的\(f\)可以由上一个儿子更新的状态转移过来
那么
\(f[u][i+j][0]=f[u][i][0]+min(f[v][j][0],f[v][j][1]+1)\)
\(f[u][i+1][1]=f[u][i][1]+min(f[v][j][1],f[v][j][0]+1)\)

但是发现以前的\(f\)是很有可能被改变的
而组成\(k=i+j\)也有很多种情况
所以在每一次更新前
我们需要再用一个数组\(g[i][j]=f[u][i][j]\)来记录上一次的情况
同时将\(f[u][i][j]\)初始化为inf
在更新过程中每次取min即可

还要注意需要两次dfs
第一次来预处理,扫一遍数统计叶子结点的个数
而我们不能用叶子结点为根,所以根很有可能不是1
得知叶子结点个数就可以知道dp枚举的范围
第二次在进行数形DP即可

H_W_Y-Coding
#include <bits/stdc++.h>
using namespace std;

const int maxn=1e4+10;
int n,head[maxn],tot=0,f[5005][5005][2],in[maxn],cnt=0,rt,siz[maxn],g[5005][2];
struct edge{
  int v,nxt;
}e[maxn*2];

inline void add(int u,int v){
  e[++tot]=(edge){v,head[u]};
  head[u]=tot;
  e[++tot]=(edge){u,head[v]};
  head[v]=tot;
}

inline int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

inline void dfs1(int u,int fa){
  for(int i=head[u];i;i=e[i].nxt){
  	int v=e[i].v;in[u]++;
  	if(v==fa) continue;
  	dfs1(v,u);
  }
  cnt+=(in[u]==1);
}

inline void dfs2(int u,int fa){
  if(in[u]==1){
  	f[u][0][0]=f[u][1][1]=0;siz[u]=1;
  	return;
  }
  bool flag=false;siz[u]=1;
  for(int i=head[u];i;i=e[i].nxt){
  	int v=e[i].v;
  	if(v==fa) continue;
  	dfs2(v,u);
  	
  	if(!flag){
  	  for(int j=0;j<=siz[v];j++)
		 f[u][j][0]=min(f[v][j][0],f[v][j][1]+1),
		 f[u][j][1]=min(f[v][j][1],f[v][j][0]+1);	
	}
	else{
	  for(int j=0;j<=min(siz[u],cnt/2);j++)
	    for(int k=0;k<2;k++)
		  g[j][k]=f[u][j][k],f[u][j][k]=0x3f3f3f3f;//初始化,后面dp的时候f会改变 
	  for(int j=0;j<=min(siz[v],cnt/2);j++)
	    for(int k=0;k<=min(siz[u],cnt/2-j);k++)
	      f[u][j+k][0]=min(f[u][j+k][0],g[k][0]+min(f[v][j][0],f[v][j][1]+1)),
	      f[u][j+k][1]=min(f[u][j+k][1],g[k][1]+min(f[v][j][1],f[v][j][0]+1));
	}
	flag=true;siz[u]+=siz[v];
  }
}

int main(){
  /*2023.7.4 H_W_Y CF581F Zublicanes and Mumocrates 树形DP*/ 
  n=read();
  for(int i=1;i<n;i++){
  	int u=read(),v=read();
  	add(u,v);
  }
  dfs1(1,0);rt=1;
  while(in[rt]==1) rt++;
  memset(f,0x3f,sizeof(f));
  dfs2(rt,0);
  printf("%d\n",min(f[rt][cnt/2][0],f[rt][cnt/2][1]));
  return 0;
}

数位DP(Digit DP)

状压DP

标签:head,ch,20230703,int,括号,2n,动态,DP
From: https://www.cnblogs.com/hewanying0622/p/17525645.html

相关文章

  • WordPress数据表结构
    如果是一个普通的用户,不需要了解wordpress数据库的结构。但是,如果你正在写一个插件,你应该会对wordpress如何处理它的数据和关系感兴趣。如果你已经尝试使用已经存在的wordpressapi去访问你需要的数据,但不直接访问数据库的情况下,这是不可能的,WordPress的提供WPDB的类,使这项任务变......
  • DP: 0-1背包,完全背包
    见:『一文搞懂完全背包问题』从0-1背包到完全背包,逐层深入+推导-零钱兑换-力扣(LeetCode)0-1背包:dp[i][w]=minmax(dp[i-1][w],dp[i-1][w-wi]+vi)完全背包dp[i][w]=minmax(dp[i-1][w],dp[i][w-wi]+vi)即完全背包可以是重复选。另外,通常可以简化2D数组到1D,因为......
  • Oracle的expdp导出、impdp导出命令
    expdp在源oracle所在服务器执行如下步骤:1、手动创建目录 mkdir-p/home/oracle/mydata2、将目录授权给用户 cd/home/oracle chown-Roracle:oinstallmydata3、oracle用户切换并使用管理员登陆oracle su-oracle sqlplus/assysdba4、源库创建directory createdirectorym......
  • 【dp,建模】AGC032D Rotation Sort
    ProblemLink有一个长为\(n\)的排列\(p\),给定\(A,B\),你每次可以做以下两种操作之一:选取\(l,r\),将\(p[l:r]\)循环右移,代价为\(A\);选取\(l,r\),将\(p[l:r]\)循环左移,代价为\(B\)。求将\(p\)排序所需的最小代价。\(n\le5000\)。技巧:循环移位→插入→实数坐......
  • 集群监管-USDP(智能大数据平台)
    UCloudSmartDataPlatform(简称USDP),是UCloud推出的智能化、轻量级、适用于私有化部署至客户本地的大数据基础服务平台,通过自研的USDPManager管理工具,支持用户创建大数据集群,在集群中部署Hadoop、Hive、HBase、Spark、Flink、Presto、Atlas、Ranger等众多开源大数据组件,并......
  • 7.17~7.18 DP专场
    CF1814EChainChips好久没写这种题了~~不带修时,为了让总距离和最短,考虑让相邻的车互换位置,但如果单纯这样有可能剩下一辆车,那就让相邻的三辆车换一下。发现当车的个数\(x\ge4\)时,都可以拆成\(2\)辆或\(3\)辆车。对应到边就是只能选相邻的一条边或两条边。设\(dp_i\)......
  • ThreadPoolExecutor线程池用法简介
    ThreadPoolExecutor 是Java中用于管理线程池的类,它提供了一种方便的方式来执行多线程任务。通过使用线程池,我们可以有效地管理和复用线程,提高程序的性能和资源利用率。下面是 ThreadPoolExecutor 线程池的详细用法介绍:创建线程池对象:ThreadPoolExecutorexecutor=ne......
  • 第九节 动态规划 - 1
    简介动态规划(DynamicProgramming,DP)及其解决的问题、根据其设计的算法及优化。动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。由于动态规划并不是某种具体的算法,而是一种解决特定问题的方法,因此它会出现在各式各样的数据结构中,与之相关的题目......
  • 加载器、链接器、动态链接器概念
    动态链接器:共享库(sharedlibrary)是致力于解决静态库缺陷的一个现代创新产物。共享库是一个目标模块,在运行或加载时,可以加载到任意的内存地址,并和一个在内存中的程序链接起来。这个过程称为动态链接(dynamiclinking),是由一个叫做动态链接器(dynamiclinker)的程序来执行的。链接器:......
  • Linux的nm查看动态和静态库中的符号
    功能列出.o.a.so中的符号信息,包括诸如符号的值,符号类型及符号名称等。所谓符号,通常指定义出的函数,全局变量等等。 使用nm[option(s)][file(s)]有用的options:-A在每个符号信息的前面打印所在对象文件名称;-C输出demangle过了的符号名称;-D打印动态符号;-l使用对......