DP模板收录
这里主要收录一些DP的模板
啊我还是太弱了居然要收录模板
1.各种简单背包
1 //01背包 2 int v[],w[],f[];//价值,重量,DP 3 for(int i=1;i<=n;i++) 4 { 5 for(int j=m;j>=0;j--) 6 { 7 if(j>=w[i]) 8 { 9 f[j]=max(f[j],f[j-w[i]]+v[i]); 10 } 11 } 12 } 13 14 //完全背包 15 int v[],w[],f[];//价值,重量,DP 16 for(int i=1;i<=n;i++) 17 { 18 for(int j=0;j<=m;j++) 19 { 20 if(j>=w[i]) 21 { 22 f[j]=max(f[j],f[j-w[i]]+v[i]); 23 } 24 } 25 } 26 27 //多重背包 28 int v[],w[],f[],t[],wl[],vl[]; //价值,重量,DP,数量,拆包后的重量与价值 29 int cnt=0; 30 for(int i=1;j<=n;i++) 31 { 32 int k=1; 33 while(t[i]>k) 34 { 35 t[i]-=k; 36 wl[++cnt]=k*w[i]; 37 vl[cnt]=k*v[i]; 38 k<<=1; 39 } 40 w[++cnt]=w[i]*t[i]; 41 v[cnt]=w[i]*t[i]; 42 } 43 for(int i=1;i<=cnt;i++) 44 { 45 for(int j=m;j>=0;j--) 46 { 47 if(j>=wl[i]) 48 { 49 f[j]=max(f[j],f[j-wl[i]]+vl[i]); 50 } 51 } 52 }
2.悬线法DP
啊这是用来求最大矩形的
1 //悬线法求最大矩形 2 //适用于01矩阵内求由1构成的最大矩形(正方形)问题 3 //LUOGU P1169 求m*n中最大01相间的正方形与矩形 4 #include<bits/stdc++.h> 5 using namespace std; 6 const int maxn=2200; 7 char s; 8 int l[maxn][maxn],r[maxn][maxn],up[maxn][maxn],map[maxn][maxn]; 9 //left[i][j]:代表从(i,j)(i,j)能到达的最左位置 10 //right[i][j]right[i][j]:代表从(i,j)(i,j)能到达的最右位置 11 //up[i][j]up[i][j]:代表从(i,j)(i,j)向上扩展最长长度. 12 int n,m,x,y,z,ans1,ans2; 13 int main() 14 { 15 scanf("%d%d",&n,&m); 16 for(int i=1;i<=n;i++) 17 for(int j=1;j<=m;j++)//初始化 18 { 19 scanf("%d",&map[i][j]); 20 l[i][j]=r[i][j]=j; 21 up[i][j]=1; 22 } 23 for(int i=1;i<=n;i++) 24 for(int j=2;j<=m;j++) 25 { 26 if(map[i][j]!=map[i][j-1])//处理l 27 l[i][j]=l[i][j-1]; 28 } 29 for(int i=1;i<=n;i++) 30 for(int j=m-1;j>=1;j--) 31 { 32 if(map[i][j]!=map[i][j+1])//处理r 33 r[i][j]=r[i][j+1]; 34 } 35 for(int i=1;i<=n;i++) 36 for(int j=1;j<=m;j++) 37 { 38 if(i>1&&map[i][j]!=map[i-1][j])//需要满足的条件 39 { 40 l[i][j]=max(l[i][j],l[i-1][j]); 41 r[i][j]=min(r[i][j],r[i-1][j]); 42 up[i][j]=up[i-1][j]+1; 43 } 44 ans2=max(ans2,(r[i][j]-l[i][j]+1)*up[i][j]);//矩形 45 x=min((r[i][j]-l[i][j]+1),up[i][j]);//矩形中取正方形 46 ans1=max(ans1,(x*x));//正方形 47 } 48 printf("%d\n",ans1); printf("%d",ans2); 49 return 0; 50 }
3.状压DP
收录一些状压DP的操作
1 //计算二进制中1的个数 2 int a,cnt=0;//二进制数,1的个数 3 while(a>0) 4 { 5 a=a&(a-1); 6 cnt++; 7 } 8 9 //判断a是否是b的子集,如101001就是 111001的子集 10 int a,int b; 11 if ((b&a)==a) 12 { 13 return true; 14 } 15 16 //二进制字符串转十进制 17 int a[],m; 18 for(int i=1;i<=[],i++) 19 { 20 scanf("%d",&a[i]); 21 m=(m<<1)+a[i]; 22 } 23 //十进制转二进制字符串 24 int n,cnt=0,a[]; 25 while(n) 26 { 27 cnt++; 28 a[cnt]=n&1; 29 n=n>>1; 30 } 31 32 //判重有无相邻的1,如有无111,或101等情况 33 // 100 34 int sit[],j,k; 35 sit[j]&(sit[j]<<1);//与左边重复 36 sit[j]&(sit[j]>>1);//与右边重复 37 sit[j]&sit[k]//上下有重复 38 (sit[j]<<1)&sit[k]//左上右下有重复 39 sit[j]&(sit[k]<<1)//右上左下有重复 40 41 //判断二进制数x上第i位上是否为1 42 if(((1<<(i-1))&x)>0) 43 44 //把二进制数x的第i位的1或0改为1 45 (1<<(i-1))|x 46 47 //把二进制数x的第i位的1改为0,0改为1 48 (1<<(i-1))^x; 49 50 ////把二进制数x的第i位1改为0 51 x & ( ~( 1 << (i-1) ) ) 52 53 //把一个数字二进制下最靠右的第一个1去掉 54 x=x&(x-1); 55 56 //以二进制的形式返回最低位的1的位置(lowbit(x))并转换为 57 如 5 二进制位 0 1 0 1 那么放入lowbit 函数 为 0001=1; 58 59 如 4 二进制位 0 1 0 0 那么放入lowbit 函数 为 0100=4; 60 61 如 6 二进制位 0 1 1 0 那么放入lowbit 函数 为 0010=2; 62 return x&(-x) ;