1. 程式人生 > >完全背包——01背包方法數

完全背包——01背包方法數

ada 小細節 ace 例題 con 最優 pan total lld

這兩天搞完01背包之後學習了完全背包這個完全背包是指物品數量無限,讓自己來裝考慮一下狀態轉移f[i][j]=max(f[i-1][j])尚未選擇第i種物品,f[i][j]=max(f[i][j-w[i]+v[i]]);從第i鍵物品中選擇一個顯然狀態是由不拿當前物品上一層的最優解和當前拿這個物品的最優解來進行比較從而進行轉移。當然目標可以是maxf[n][j]或者是f[n][m]這兩種都行只不過前者可以判斷背包是否能被裝滿。

下面是二維的代碼:

技術分享圖片
#include<ctime>
#include<iostream>
#include<cstdio>
#include
<algorithm> #include<cstdio> #include<iomanip> #include<map> #include<queue> #include<stack> #include<cstring> #include<string> #include<vector> using namespace std; inline long long read() { long long x=0,f=1;char ch=getchar(); while(ch<
0||ch>9){if(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} return x*f; } const long long maxn=10001; long long f[maxn][maxn],w[maxn],v[maxn]; long long n,m; int main() { //freopen("1.in","r",stdin); m=read();n=read(); for(long long i=1
;i<=n;i++) { v[i]=read();w[i]=read(); } for(long long i=1;i<=n;i++) for(long long j=1;j<=m;j++) { f[i][j]=max(f[i][j],f[i-1][j]); if(j>=w[i])f[i][j]=max(f[i][j],f[i][j-w[i]]+v[i]); } printf("%lld\n",f[n][m]); return 0; }
View Code

而一維的完全背包是那樣子的,把f[j]=max(f[j-w[i]]+v[i]);正序來選擇因為可以在剛剛更新過的第i件物品之上再進行更新這樣的話就意味著一件物品有無數件了。不算是很懵了

下面是一維的代碼:

技術分享圖片
#include<ctime>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
const int maxn=10001;
int f[maxn],w[maxn],v[maxn];
int n,m;
int main()
{
    //freopen("1.in","r",stdin);
    m=read();n=read();
    for(int i=1;i<=n;i++)
    {
        v[i]=read();w[i]=read();
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=w[i];j<=m;j++)
        {
            f[j]=max(f[j],f[j-w[i]]+v[i]);
        }
    }
    cout<<f[m]<<endl;
    return 0;
}
View Code

又搞了一道01背包的方法數,這個還是比較簡單的個人覺得方法數的話以下面的洛谷例題為例:
技術分享圖片

求出所有背包的數量,這樣的話求助了學長,不會啊當時感覺特別困難做題沒有舉一反三的能力感覺自己還不行,靈性不夠。這很顯然是一道01背包的變形所以只要稍稍的把01背包的轉移方程改一下即可,

f[j]=f[j]+f[j-w[i]];初始化f[0]=1;這樣加上一些小細節這道題就可以被輕松a掉。

代碼:

技術分享圖片
#include<ctime>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
const int maxn=1002;
int a[7]={0,1,2,3,5,10,20};
int w[maxn],f[maxn],n=0,m=0,ans=0;
int main()
{
    //freopen("1.in","r",stdin);
    for(int i=1;i<=6;i++)
    {
        int x;
        x=read();
        for(int j=1;j<=x;j++)
        {
            w[++n]=a[i];
            m+=a[i];
        }
    }
    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=w[i];j--)
        {
            f[j]=f[j]+f[j-w[i]];//從i個數中來選和為j的有多少種方案
        }
    }
    for(int i=1;i<=m;i++)
    {
        if(f[i]!=0)ans++;
    }
    printf("Total=%d\n",ans);
    return 0;
}
View Code

完全背包——01背包方法數