【常规的01背包 POJ3624 UVA562 HDU2546 HDU3466 poj1745】

版权声明:本文为博主原创文章,未经博主允许不得转载。 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会炸的

猜你喜欢

转载自blog.csdn.net/sxy201658506207/article/details/84800449