【模板题】动态规划 3531 判断整除 2989:糖果——一定要装满的背包问题

0-1背包扩展:要求所选择的物品必须恰好装满背包。

一般思路:设计dp[i][j]为前i件物品恰好体积总和为j时的最大价值,其状态转移01背包完全一致,但初始状态变为:dp[0][0]为0,而其它dp[0][j](前0件物品体积总量为j)值均为负无穷或不存在,最终得ans=dp[n][s]

此类问题不扫描到最后一件物品没有办法得到最终结果,也无法判断之前的结果是否最接近,所以只能把状态保留下来。

3531 判断整除 点击打开链接

题目大意:一串数字,每个前面加+or-,和能否整除k

数学基础:
1、a|=b 即a=a|b  其中|为位或运算(则a、b中有一个为true则a为true)
     a&=b 即a=a&b  其中&为位与运算

2、模法分配律,即(a+b+c)%k=(a%k+b%k+c%k)%k

技巧:
1、右移100为负数腾空间(k<=100)

2、bool dp[i][j]表示到第i个数模k是否有可能等于j,最终结果为dp[N+1][0+100]

思路和代码参考:链接

AC代码:

#include 
using namespace std;
int n,k,a;
bool dp[10005][205];
int main()
{
    int i,j;
    cin>>n>>k;
    cin>>a;//节省空间的好办法
    a%=k;//数学基础2
    dp[1][100-a]=true;
    dp[1][100+a]=true;
    for(i=2;i<=n;i++)
    {
	cin>>a;
        a%=k;
        for(j=0;j<=k+100;j++)
        {
            dp[i][(j+a-100)%k+100]|=dp[i-1][j];//数学基础1
            dp[i][(j-a-100)%k+100]|=dp[i-1][j];
        }
    }
    if(dp[n][100]==true)
		cout<<"YES";
    else 
		cout<<"NO";
    return 0;
}

2989:糖果

题目大意:N个物品,每个物品重量为a[i],求满足总重量能整除k时能取得的最大重量

思路:dp[i][j]表示到第i个物品为止,%k余数为j的最大重量
初始化:dp[0][0]=0,其他初始化为-1(即不存在)
扫描余数j, 若dp[i-1][j]存在(即有余数为j的装法),讨论:
1)不取第i件物品:dp[i][j]=dp[i-1][j]

2)取第i件物品:dp[i][(j+a[i])%k]=dp[i-1][j]+a[i]

#include
#include
using namespace std;
int dp[101][101],a[101];
int main()
{
	int n,k,i,j;
	cin>>n>>k;
	memset(dp,-1,sizeof(dp));
	for (i=1;i<=n;i++)
		cin>>a[i];
	dp[0][0]=0;
	for (i=1;i<=n;i++)
		for (j=0;j=0)
			{
				dp[i][j]=max(dp[i][j],dp[i-1][j]);
				dp[i][(j+a[i])%k]=max(dp[i][(j+a[i])%k],dp[i-1][j]+a[i]);
			}
	int ans=0;
	for (i=0;i<=n;i++)
		ans=max(dp[i][0],ans);
	cout<
(在网上溜达一圈发现这道题只有我用这种思路做有点小开心O(∩_∩)O),已AC哦!

你可能感兴趣的:(dp)