揹包問題總覽(圖)

猛然心血來潮寫了一黑板的揹包問題總覽。ios

小班同志能夠根據這順序學習DP解決揹包問題。學習

這個腦圖很清楚的寫出了揹包問題的基本類別和思路(思路好像上廁所去了……)spa

總結和模板改天有空發上來。blog

ps:微軟這個掃描軟件真管用……前幾天掃身份證,今天掃黑板,很方便。ci

 

 

簡單的揹包問題(洛谷試煉場->普及練習場->動態規劃的揹包問題):get

(一)01揹包 (大部分可直接用模板解決)博客

  (1)洛谷【p1060】開心的金明 (標準的01揹包問題)string

#include<iostream>
#include<cstdio>
using namespace std;

int N,m;
int v[300],p[300];
int f[50001];
int want=0;

int main(){
    cin>>N>>m;
    for(int i=0;i<m;i++){
        cin>>v[i]>>p[i];
        p[i] *= v[i];
    }
    for(int i=0;i<m;i++){
        for(int j=N;j>v[i];j--){
            if(f[j-v[i]]+p[i]>f[j]){
                f[j]=f[j-v[i]]+p[i];
            }
        }
    }
    cout<<f[N];
    return 0;
} 

  (2)洛谷【p1048】採藥 (標準的01揹包問題)it

#include<cstdio>
#include<iostream>
using namespace std;
int T,m;
int w[1000],c[1000],f[100000];

int main()
{
  cin>>T>>m;
  for(int i=1;i<=m;i++){
    cin>>w[i]>>c[i];
  }
  for(int i=1;i<=m;i++){
    for(int j = T;j>=w[i];j--){
      if(f[j-w[i]]+c[i]>f[j]){
        f[j]= f[j-w[i]]+c[i];
      }
    }
  }
  cout<<f[T];
}

  (3)洛谷【p1049】裝箱問題 (01揹包問題,物品重量和價值相同)io

#include<iostream>
#include<cstdio>
using namespace std;
int v,n;
int c[35],f[100000];
int main()
{
  cin>>v>>n;
  for(int i =1;i<=n;i++){
    cin>>c[i];
  }
  for(int i =1;i<=n;i++){
    for(int j=v;j>=c[i];j--){
      if(f[j-c[i]]+c[i]>f[j]){
        f[j]=f[j-c[i]]+c[i];
      }
    }
  }
  cout<<v-f[v];
}

(二)揹包方案計數:

  (2)洛谷【P1164】 小A點菜 (01揹包解決方案計數問題)

#include<iostream>
#include<cstdio>
using namespace std;
int c[2000];
long long int f[100000];
int n,m;
int main(){
  cin>>n>>m;
  for(int i=0;i<n;i++){
    cin>>c[i];
  }
  f[0]=1;
  for(int i =0;i<n;i++){
    for(int j=m;j>=c[i];j--){
      f[j]+=f[j-c[i]];
      }
    }
  cout<<f[m];
}

(三)依賴揹包問題:

  (1)洛谷 【p1064】金明的預算方案 (樹狀DP)

/*代碼參考神犇博客*/
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int M = 3276;
const int S = 80;
vector<int> vct[S];
vector<pair<int, int> > groups[S];
int dp[M], n, m, w[S], v[S], d[S];
main()
{
    scanf("%d %d", &m, &n);
    m /= 10;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d %d %d", &w[i], &v[i], &d[i]);
        w[i] /= 10;
        v[i] *= w[i];
        if(d[i])
           vct[d[i]].push_back(i);
    }
    int cnt = 0;
    for(int i = 1; i <= n; i++)
    {
        if(d[i] == 0)
        {
            memset(dp, 0, sizeof(dp));
            dp[w[i]] = v[i];
            int sum = w[i];
            for(int j = 0; j < vct[i].size(); j++)
            {
                int dx = vct[i][j];
                sum += w[dx];
                for(int k = sum; k >= w[i]; k--)
                    if(dp[k] != 0)
                        dp[k + w[dx]] = max(dp[k] + v[dx], dp[k + w[dx]]);
            }
            for(int j = w[i]; j <= sum; j++)
                if(dp[j])
                    groups[cnt].push_back(make_pair(j, dp[j]));
            cnt++;
        }
    }
    memset(dp, 0, sizeof(dp));
    for(int i = 0; i < cnt; i++)
        for(int j = m; j >= 0; j--)
            for(vector<pair<int, int> >::iterator it = groups[i].begin(); it != groups[i].end(); it++)
                if(j >= it ->first)
                    dp[j] = max(dp[j], dp[j - it ->first] + it ->second);
    printf("%d\n", dp[m] * 10);
}

(四)徹底揹包問題:

  (1)洛谷 【p1616】瘋狂的採藥 (每種物品有無限數量的揹包問題)

#include<iostream>
#include<cstdio>
using namespace std;
int m,n;
int f[100010],w[10010],c[10010];
int main(){
  cin>>m>>n;
  for(int i=1;i<=n;i++){
    cin>>w[i]>>c[i];
  }
  for(int i=1;i<=n;i++){
    for(int j = w[i];j<=m;j++){
      if(f[j-w[i]]+c[i]>f[j]) f[j] = f[j-w[i]]+c[i];
    }
  }
  cout<<f[m];
}
相關文章
相關標籤/搜索