首页 > 技术文章 > DP模板收录

xwx2354672579 2019-08-26 19:39 原文

这里主要收录一些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 }
悬线法DP

 

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))并转换为 
575  二进制位 0 1 0 1       那么放入lowbit  函数 为  0001=158 
594  二进制位 0 1 0 0       那么放入lowbit  函数 为 0100=460 
616  二进制位 0 1 1 0       那么放入lowbit  函数 为 0010=262 return x&(-x) ;
状压DP

 

推荐阅读