P1057
就是要找到两子状态,然后定好开头状态
求可能是从左边,可能是右边
#include<iostream>
using namespace std;
int f[31][31]={1};
int main()
{
int m,n;//m是次数,n 是人数
cin>>n>>m;
for(int i=1;i<=m;i++)
{
for(int j=0;j<n;j++)
{
f[i][j]=f[i-1][(j+1)%n]+f[i-1][(j-1+n)%n];
}
}
cout<<f[m][0];
}
有一个很妙的就是解决越界问题的,取余了吧
P1216
一个逐步递推就好了,可以用一个滚动数组来节省空间
选一个最大的加上自身
#include<iostream>
#include<math.h>
using namespace std;
int a[1001][1001] ;
int main()
{
int m;
cin>>m;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=i;j++)
{
cin>>a[i][j];
}
}
for(int i=m-1;i>=1;i--)
{
for(int j=1;j<=i;j++)
{
a[i][j]=max(a[i+1][j],a[i+1][j+1])+a[i][j];
}
}
cout<<a[1][1];
}
逃不掉的背包问题
01背包,目的是最大价值,两重循环,第一重循环是背包里面物品的个数,第二重是背包体积开始向前
然后判断加还是不加,加的话要减去体积,然后加上价值
#include<iostream>
#include<cmath>
using namespace std;
int dp[10001];
int main()
{
int T,M,t,m;
cin>>T>>M;
for(int i=1;i<=M;i++)
{
cin>>t>>m;
for(int j=T;j>=t;j--)
{
dp[j]=max(dp[j],dp[j-t]+m) ;
}
}
cout<<dp[T];
return 0;
}
P1060
#include<iostream>
#include<math.h>
using namespace std;
int dp[10000000];
int main()
{
int N,M,a,b,c;
cin>>N>>M;
for(int i=1;i<=M;i++)
{
cin>>a>>b;
c=a*b;
for(int j=N;j>=a;j--)这里是a,包的承载量和价钱有关
dp[j]=max(dp[j],dp[j-a]+c);
}
cout<<dp[N];
return 0;
}
P1049
这里的价值和个数都是体积
#include<iostream>//价值和体积等价
#include<math.h>
using namespace std;
int dp[476587698];
int main()
{
int V,n,a;
cin>>V>>n;
for(int i=1;i<=n;i++)
{cin>>a;
for(int j=V;j>=a;j--)
{
dp[j]=max(dp[j],dp[j-a]+a);
}
}
cout<<V-dp[V];
}
P1802
就是说要分个类,不同条件下有不同的值
,设置结构体调用的时候要想小心一点
#include<iostream>
using namespace std;
long long int f[10086];
struct node
{
int lose;
int win;
int ge;
}aa[10086];
int main()
{
int n,x;
cin>>n>>x;
for(int i=1;i<=n;i++)
{
int a,b,c;
cin>>a>>b>>c;
aa[i].lose =a;
aa[i].win =b;
aa[i].ge =c;
}
for(int i=1;i<=n;i++)
{
for(int j=x;j>=0;j--)
{
if(j>=aa[i].ge )
{
f[j]=max(f[j]+aa[i].lose ,f[j-aa[i].ge ]+aa[i].win );
}
else
{
f[j]=f[j]+aa[i].lose ;
}
}
}
cout<<f[x]*5;
}
P1734
背包总体积就是数的大小,个数就是小于它的这些数字,然后价值就是自己打个表循环赋值
//s是背包的容量,价值是和
#include<iostream>
int a[145435676],dp[2135564];
using namespace std;
int main()
{
int S;
cin>>S;
for(int i=1;i<S;i++)
{
for(int j=1;j<i;j++)
{if(i%j==0)
a[i]+=j;
}
}
for(int i=1;i<=S;i++)
for(int j=S;j>=i;j--)
{
dp[j]=max(dp[j],dp[j-i]+a[i]);
}
cout<<dp[S];
return 0;
}
P1050
本意是要求最少用的精力,把石头都搬走,就是说把石当作背包的总体积,但是就是说精力要最小,有点难理解
可以把精力当作总的价值,毕竟这个不需要变成001,然后石头就是物品,然后再去查正好搬到ok时候的精力
#include<iostream>
#include<string.h>
using namespace std;
int dp[19977],vv,tl,flag;
int main()
{
int v,n,c;
cin>>v>>n>>c;
for(int i=1;i<=n;i++)///多少块是物品可能性
{
cin>>vv>>tl;
for(int j=c;j>=tl;j--)//这个是体力,也就是背包的价值
{
dp[j]=max(dp[j],dp[j-tl]+vv);//每次都是最少的 ,所以一开始要设置大
}
}
for(int i=1;i<=c;i++)
{
if(dp[i]>=v)
{cout<<c-i;
flag=1;
break;
}
}
if(flag==0)
cout<<"Impossible";
}
P1466
这种求方法的一定要记得赋值为1;
这种就要分成两份,然后总的物件是数字,总价值是他们的和,然后每一次都是选自己和不选自己;
//背包能装物品n/2,装物品价值就是他们和
#include<iostream>
using namespace std;
long long int dp[1002]={1};/long long 吞了一个点
int main()
{
int n,m;
cin>>n;
m=(n+1)*n/2;
if(m%2==1)
{
cout<<0;
return 0;
}
for(int i=1;i<=n;i++)
{
for(int j=m/2;j>=i;j--)
{
dp[j]+=dp[j-i];
}
}
cout<<dp[m/2]/2;
return 0;
}
P1616
是个完全背包,就是要从头往后第二轮循环
#include<bits/stdc++.h>
using namespace std;
long long int dp[100010];
int N,M,a,b;
int main()
{
cin>>N>>M;
for(int i=1;i<=M;i++)
{
cin>>a>>b;
for(int j=a;j<=N;j++)
{
dp[j]=max(dp[j],dp[j-a]+b);
}
}
cout<<dp[N];
return 0;
}
P1679
求最小的,就是每一次min,然后所以一开始要赋值最大,然后记得第一个是0,至于有几个物品就自己循环出来
#include<iostream>
#include<cstring>
using namespace std;
int dp[100010],a[123];
int main()
{
long int m,n;
cin>>m;
memset(dp,61,sizeof(dp));
dp[0]=0;
dp[1]=1;
for(int i=1;i<=m;i++)
{
a[i]=i*i*i*i;
if(a[i]>=m)
{
n=i;
break;
}
}
for(int i=1;i<=n;i++)
{
for(int j=a[i];j<=m;j++)
dp[j]=min(dp[j],dp[j-a[i]]+1);
}
cout<<dp[m];
}
P1757
分组背包,就是每一次每一组要选出来最好的然后去参与,每一次都i要比,每一次都出来最好的
bag的结构体,要放入一个组数
#include<bits/stdc++.h>
using namespace std;
struct Bag
{
int a[1010];
int b[1010];
int w;
}c[1001];
int dp[1010];
int main()
{
int M,N,p=0;
cin>>M>>N;
for(int i=1;i<=N;i++)
{
int x,y,z;
cin>>x>>y>>z;
p=max(p,z);
c[z].w++;
c[z].a[c[z].w]=x;///记住它
c[z].b[c[z].w]=y;///记住她
}
for(int i=1;i<=p;i++)//几个组
{
for(int j=M;j>=0;j--)//价值 {
for(int k=1;k<=c[i].w;k++)//每一个组的里面有几个
{
if(j-c[i].a[k]>=0)
dp[j]=max(dp[j],dp[j-c[i].a[k]]+c[i].b[k]);
}
}
}
cout<<dp[M];
return 0;
}
P1064
放一个40分的我觉得完美的精明预算方案
就是说要分成四个组,每一个包里面有四个组,四个组就是用数组来表示
在这里插入代码#include<iostream>
using namespace std;
int dp[12345]={0};
struct node
{
int a[10202];
int b[10202];
int w;
}c[10202];
int main()
{
int m,n,p;
cin>>m>>n;
for(int i=1;i<=n;i++)
{
int x,y,z;
cin>>x>>y>>z;
if(z==0)
{
c[i].w=1;
c[i].a[1]=x;
c[i].b[1]=y*x;
}
else
{
if(c[z].w ==1)
{
c[z].w =2;
c[z].a[2] =x+c[z].a[1];
c[z].b[2] =x*y+c[z].b[1];
}
else
{
c[z].a[3]=c[z].a[1]+x;
c[z].b[3]=c[z].b[1]+x*y;
c[z].a[4]=c[z].a [2]+x;
c[z].b [4]=c[z].a [2]+x*y;
c[z].w=4; }
}
}
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
for(int k=1;k<=c[i].w ;k++)
{
if(j>=c[i].a[k])
dp[j]=max(dp[j],dp[j-c[i].a[k]]+c[i].b[k]) ;
}
}
}
cout<<dp[m];
return 0;
}