小A点菜

传送门

思路 1 1 1

十分经典的一道DP题。
转移方程式为:

f[j]+=f[j-a[i]];

我们首先定义 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个菜品恰好花费 j j j元的方案数。
当我们买第 i i i道菜时:

f[i][j]+=f[i-1][j-a[i]];

当我们不买第 i i i道菜时:

f[i][j]+=f[i-1][j];

但当第 i i i道菜的价格被就是 j j j时,就可以只买自己,这种情况应该其实包含在 1 1 1中,但是由于 f [ i ] [ 0 ] = 0 f[i][0]=0 f[i][0]=0,所以不会算入这种情况。所以我们就要把 f [ i ] [ 0 ] f[i][0] f[i][0]刚开始就赋值为 1 1 1
代码

#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],f[105][10005];

int main() {
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=0;i<=n;i++) f[i][0]=1;//注意0 
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=m;j++) {
			f[i][j]+=f[i-1][j];
			if(j>=a[i]) f[i][j]+=f[i-1][j-a[i]];
		}
	}
	printf("%d",f[n][m]);
	return 0;
}

我们可以优化为一维。
但我们的第二重循环必须逆序跑,因为我们一维的转移方程式为:

f[j]+=f[j-a[i]];

如果跑正序,我们的 f [ j ] f[j] f[j]还没有更新, f [ j − a [ i ] ] f[j-a[i]] f[ja[i]]反倒先更新了,这样的话与题意的“每种菜只有一份”相冲。如果没有这句话,我们就可以正序了。

#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],f[10005];

int main() {
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	f[0]=1; 
	for(int i=1;i<=n;i++) {
		for(int j=m;j>=a[i];j--)
			f[j]+=f[j-a[i]];
	}
	printf("%d",f[m]);
	return 0;
}

思路 2 2 2

( 1 ) i f ( j = = 第 i 道 菜 的 价 格 )   f [ i ] [ j ] = f [ i − 1 ] [ j ] + 1 ; (1)if(j==第i道菜的价格)\ f[i][j]=f[i-1][j]+1; 1if(j==i) f[i][j]=f[i1][j]+1;

( 2 ) i f ( j > 第 i 道 菜 的 价 格 )   f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 第 i 道 菜 的 价 格 ] ; (2)if(j>第i道菜的价格)\ f[i][j]=f[i-1][j]+f[i-1][j-第i道菜的价格]; 2if(j>i) f[i][j]=f[i1][j]+f[i1][ji];

( 3 ) i f ( j < 第 i 道 菜 的 价 格 )   f [ i ] [ j ] = f [ i − 1 ] [ j ] ; (3)if(j<第i道菜的价格)\ f[i][j]=f[i-1][j]; 3if(j<i) f[i][j]=f[i1][j];

说的简单一些,这三个方程,每一个都是在吃与不吃之间抉择。若钱充足,办法总数就等于吃这道菜的办法数与不吃这道菜的办法数之和;若不充足,办法总数就只能承袭吃前 i − 1 i-1 i1道菜的办法总数。依次递推,在最后,我们只要输出 f [ n ] [ m ] f[n][m] f[n][m]的值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,a[105],f[105][10005];

int main() {
	scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) {
    	for(int j=1;j<=m;j++) {
			if(j==a[i])f[i][j]=f[i-1][j]+1;
        	else if(j>a[i]) f[i][j]=f[i-1][j]+f[i-1][j-a[i]];
        	else f[i][j]=f[i-1][j];
    	}
	}
	printf("%d",f[n][m]);
    return 0;
}
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页