常用背包dp模板(未完待续)

这里是作者的留言板

部分板子优化中...
你好哇,我是flypig114;
先说一句:本人仅在博客园发表博客,其他皆为盗版;
可能某些人能看出上面那句是什么意思,我也不多说了;
代码里有变量(只不过最近会改变量名使其更正规)数组的注释,so...不多废话,直接上正题!;


01背包

这里是题目AWA:
\(N\)件物品和一个容量是\(M\)的背包。每件物品只能使用一次。第 \(i\)件物品的体积是\(w\),价值是\(v\)
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。

输入格式
第一行两个整数,\(N\)\(M\),用空格隔开,分别表示物品数量和背包容积。接下来有 \(M\)行,每行两个整数\(wi\),\(vi\),用空格隔开,分别表示第\(i\)件物品的体积和价值。

输出格式
输出一个整数,表示最大价值。
数据范围
\(0<M,N≤10000\)
\(0<vi,wi≤10000\)
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例
8

无优化

#include<bits/stdc++.h>
using namespace std;
#define ll int     // 为了方便修改类型
const ll N = 1000; // 辅助定义数组
ll n, m;           // n是物品数量   m是背包容量
ll v[N], w[N];     // v是物品的价值   w是物品的重量
ll i, j, dp[N][N]; // 辅助计算,dp[i][j]表示前i个物品放入容量为j的背包的最大价值
int main()
{
	//背包与DP的开始
    cin >> n >> m;
    for (i = 1; i <= n; i++)
    {
        cin >> w[i] >> v[i];
    }
    //进行处理
    for (i = 1; i <= n; i++)
        for (j = m; j >= 0; j--)//从背包容量开始,保证每个物品都考虑过
        {
            if(j>=w[i])//判断是否可以放入
            {
                dp[i][j] = max(dp[i - 1][j - w[i]] + v[i], dp[i - 1][j]);//判断是否放入,dp[i-1][j-w[i]]+v[i]更大则放入
            }  
            else
            {
                dp[i][j] = dp[i - 1][j];//不放入
            }              
        }
    //结束首战告捷
    cout << dp[n][m];
    return 0;
}

一维数组优化

#include<bits/stdc++.h>
using namespace std;
#define ll int//为了方便修改类型
const ll N=1e5;//辅助定义数组
ll n, m;       // n是物品数量   m是背包容量
ll v[N], w[N];  // v是物品的价值   w是物品的重量
ll i, j, dp[N]; // 辅助计算
int main()
{
	//难度上升需要新方法
    cin >> n >> m;
    for (i = 1; i <= n; i++)
    {
        cin >> w[i] >> v[i];
    }
    //重中之重(好像就这里改了)
    for (i = 1; i <= n; i++)
    {
        for (j = m; j >= 0; j--)
        {
            if(j>=w[i])
            {
                dp[j] = max(dp[j - w[i]] + v[i], dp[j]);
            }
        }
    }   
    //可以输出了
    cout << dp[m] << endl;
    return 0;
}

完全背包问题:

这里是题目AWA:
\(M\)件物品和一个容量是\(N\)的背包。每件物品可使用无限次。第\(i\)件物品的体积是\(v\),价值是\(w\)
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。

输入格式
第一行两个整数,\(N\)\(M\),用空格隔开,分别表示背包容积和物品数量。接下来有 \(M\)行,每行两个整数\(vi\),\(wi\),用空格隔开,分别表示第\(i\)件物品的体积和价值。

输出格式
输出一个整数,表示最大价值。
数据范围
\(0<M≤30,0<N≤200\)
\(0<vi,wi≤10000\)
输入样例
10 4
2 1
3 3
4 5
7 9
输出样例
12

#include<bits/stdc++.h>
using namespace std;
#define ll int   // 为了方便修改类型
const ll N = 1e5; // 辅助定义数组
ll n, m;       // n是背包容量   m是物品数量
ll v[N], w[N]; // v是物品的重量   w是物品的价值
ll dp[N], i, j; // 辅助计算
int main(){
    cin >> n>> m;
    // 输入
    for (i = 1; i <= m; i++)
    {
        cin >> v[i] >> w[i];
  }
  //完全背包启动!
  for (i = 1; i <= m; i++)
  {
      for (j = 0; j <= n; j++)
      {
          if (j >= v[i])
              dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
      }
	}
  //简简单单的输出
    cout << dp[n] << endl;
    return 0;
}

多重背包问题:

无优化

#include<bits/stdc++.h>
using namespace std;
#define ll int   // 为了方便修改类型
const ll N=100000;//辅助定义数组
ll m, n;          // n是背包容量   m是物品数量
ll v[N], w[N], s[N]; // v是物品的重量   w是物品的价值   s是物品的数量。
ll dp[N], i, j, k; // 辅助计算
int main()
{
	//输入顺序按需求更改(不会有人真题都不看就套板子吧?)
    cin >> m >> n;
    for (i = 1; i <= m; i++)
    {
        cin >> w[i] >> v[i] >> s[i];
    }
	//熟悉的流程
    for (i = 1; i <= m; i++)
    {
        for (j = n; j >= v[i]; j--) //倒序是为了防止重复计算
        {
            for (k = 1; k * v[i] <= j && k <= s[i]; k++)//因为每个物品可以取多次,所以需要循环
            {
                dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);  
            }
		}
	}
    //结束了? 
    cout << dp[n] << endl;  
    return 0;   
    //结束了。
}

二进制优化

#include<bits/stdc++.h>
using namespace std;
#define ll int   // 为了方便修改类型
const ll N=100000;//辅助定义数组
ll m, n;          // n是背包容量   m是物品数量
ll v[N], w[N], s[N]; // v是物品的重量   w是物品的价值   s是物品的数量。
ll dp[N], i, j, k; // 辅助计算
int main()
{
    cin >> m >> n;
    for (i = 1; i <= m; i++)
    {
        cin >> v[i] >> w[i] >> s[i];
    }
    //拆分方式更加优美
    for (i = 1; i <= m; i++)
    {
        for (k = 1; k <= s[i]; k *= 2)
        {
            for (j = n; j >= k * v[i]; j--)
            {
                dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
            }
            s[i] -= k;
        }
        for (j = n; j >= s[i] * v[i]; j--)
        {
            dp[j] = max(dp[j], dp[j - s[i] * v[i]] + s[i] * w[i]);
            }
	}
	//我的回合!输出!
    cout << dp[n] << endl;  
    return 0;   
}

混合背包问题

#include<bits/stdc++.h>
using namespace std;
#define ll int  // 为了方便修改类型
const ll N=100000;// 辅助定义数组
ll m, n;// n是背包容量   m是物品数量
ll w[N], v[N], s[N];//w物品的价值,v物品的体积,s物品的数量
ll dp[N], i, j, k;//辅助计算
/*多重背包*/
void somebag()
{
    for (k = 1; k <= s[i]; k *= 2)
    {
        for (j = n; j >= k * v[i]; j--)
        {
            dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]);
        }
        s[i] -= k;
		}
        for (j = n; j >= s[i] * v[i]; j--)
        {
            dp[j] = max(dp[j], dp[j - s[i] * v[i]] + s[i] * w[i]);
    }
    return;
}
/*完全背包*/
void allbag()
{
	 for (j = 0; j <= n; j++)
      {
          if (j >= v[i])
          {
          	dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
		  }
      }
      return;
}

int main(){
    cin >> n >> m;
    for (i = 1; i <= m; i++)
    {
        cin >> v[i] >> w[i] >> s[i];
    }
	for(i=1;i<=m;i++)
	{
		if(s[i]!=0)
        {
            somebag(); // 多重背包可以代替01背包
        }
		else
		{
            allbag(); // 物品可以无限取,使用完全背包
        }
	}
    cout << dp[n];
    return 0;
}
posted @ 2024-08-31 11:44  flypig114  阅读(121)  评论(0编辑  收藏  举报