版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sxy201658506207/article/details/84800449
POJ3624
有N个物品,分别有不同的重量Wi和价值Di,Bessie只能带走重量不超过M的物品,要是总价值最大,并输出总价值
//#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
using namespace std;
int dp[maxn];
int c[maxn];
int w[maxn];
int main()
{
int n,m;
while(cin>>n>>m)
{
for(int i=0; i<n; ++i){cin>>c[i]>>w[i];}
for(int i=0; i<n; ++i)
for(int j=m; j>=c[i]; --j)
dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
cout<<dp[m]<<endl;
}
return 0;
}
UVA562
给定n个硬币,要求将这些硬币平分以使两个人获得的钱尽量多,求两个人分到的钱最小差值。
#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll moad=1e9+7;
const int maxn=1e6+10;
int dp[maxn];
int w[maxn];
int vis[maxn];
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
int sum=0;
for(int i=0;i<n;++i)cin>>w[i],sum+=w[i];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i)
{
for(int j=sum/2;j>=w[i];--j)
{
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
}
int __=dp[sum/2],_;
_=sum-__;
cout<<abs(__-_)<<endl;
}
return 0;
}
HDU2546
这题看上去就知道是01问题了,可是开始怎么转化都没有转化为正确的01背包姿势
因为没有明显的给出来一个背包的容量(做完之后,看出来其实是给出来的,就是这个m-5),然后我wa的姿势是找所有物品的价值总和去作为容量
撒了一眼题解看是m-5,才知道可以用这个-5剩下的钱去01背包买更多的东西,最后加上那个5块钱去买加个最大的物品
这个5块好像用到了贪心的思想 mmp
总结:转化为正确的01问题姿势是关键
#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+10;
int dp[maxn];
int w[1005];
int main()
{
int n,m;
while(cin>>n,n)
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i) cin>>w[i];
cin>>m;
if(m<5){cout<<m<<endl;continue;}
sort(w,w+n);
int _now=m-5;
for(int i=0;i<n-1;++i)
{
for(int j=_now;j>=w[i];--j)
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
cout<<m-(w[n-1]+dp[_now])<<endl;
}
return 0;
}
#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e6+10;
int dp[maxn];
int w[1005];
int main()
{
int n,m;
while(cin>>n,n)
{
int ans=0;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i) cin>>w[i],ans+=w[i];
cin>>m;
if(m<5){cout<<m<<endl;continue;}
for(int i=0;i<n;++i)
{
for(int j=ans;j>=w[i];--j)
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
cout<<m-dp[ans]<<endl;
}
return 0;
}
HDU3466
先前得01背包问题都是占用多大空间,有多大空间就可以直接进行放入,而这个有个限制体条件
当容量低于特定值得时候就不可以放入,那这样进行放入得原则就是 需要的容量/本身占有得容量大小 这个值越小越好,所谓得性价比越高越好嘛
还有要注意的一点就是当 背包容量小于给的特定值得时候就不可以进行更新dp数组了
#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll moad=1e9+7;
const int maxn=1e6+10;
int q[maxn];
int c[maxn];
int w[maxn];
int dp[maxn];
struct node
{
double c,q,w;
}point[maxn];
bool cmp(node a,node b)
{
//return a.q-a.c<b.q-b.c;
//return a.c*b.q<b.c*a.q;
return a.q/a.c<=b.q/b.c;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;++i)cin>>point[i].c>>point[i].q>>point[i].w;
sort(point,point+n,cmp);
// for(int i=0;i<n;++i)
// cout<<point[i].c<<' '<<point[i].q<<' '<<point[i].w<<endl;
for(int i=0;i<n;++i)
{
for(int j=m;j>=point[i].q;--j)
{
dp[j]=max(dp[j],dp[j-int(point[i].c)]+int(point[i].w));
}
}
cout<<dp[m]<<endl;
}
return 0;
}
poj1745
给你n个数,经过加减的操作,看能不能整除K。
dp[i][j]代表前i个数字整除 m 的余数为 j
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 10005
using namespace std;
int main()
{
int N,K;
cin>>N>>K;
int a[X];
for(int i=1;i<=N;++i)
{
scanf("%d",&a[i]);
a[i]%=K;
}
int dp[X][K];
memset(dp,0,sizeof(dp));
//if(a[1]<0)
// a[1]+=K;
a[1]=(a[1]+K)%K;
dp[1][a[1]]=1;
for(int i=2;i<=N;++i)
{
for(int j=0;j<K;++j)
{
if(dp[i-1][j])
{
/* if(j+a[i]>=0)
dp[i][j+a[i]]=1;
else
dp[i][j+a[i]+K]=1;
if(j>=a[i])
dp[i][j-a[i]]=1;
else
dp[i][j-a[i]+K]=1;*/
dp[i][(j+a[i]+K)%K]=1;//保证下标大于0
dp[i][(j-a[i]+K)%K]=1;
}
}
}
if(dp[N][0])
cout<<"Divisible"<<endl;
else
cout<<"Not divisible"<<endl;
return 0;
}
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 10005
using namespace std;
long long POW(int a,int b)
{
long long ans=1;
while(b){
if(b&1)
{
ans*=a;
}
a*=a;
b>>=1;
}
return ans;
}
int main()
{
int N,K;
cin>>N>>K;
int a[X];
for(int i=0;i<N;++i)
{
scanf("%d",&a[i]);
}
long long n=POW(2,N-1);
for(int i=0;i<n;++i)
{
int sum=a[0];//cout<<a[0];
for(int j=0;j<N-1;++j)
{
if((i>>j)&1)
{//cout<<'-'<<a[j+1];
sum+=a[j+1];
}
else
sum-=a[j+1];//,cout<<'+'<<a[j+1];
}
//cout<<'='<<sum<<"*****"<<sum%K<<endl;
if(!(sum%K))//!的优先级比%的高
{
cout<<"Divisible"<<endl;
return 0;
}
//cout<<endl;
}
cout<<"Not divisible"<<endl;
return 0;
}
//这个方法是对的,可是在这儿N是10000算出来的n是2^10000会炸的