• 小A点菜


    传送门

    思路(1)

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

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

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

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

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

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

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

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

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

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

    说的简单一些,这三个方程,每一个都是在吃与不吃之间抉择。若钱充足,办法总数就等于吃这道菜的办法数与不吃这道菜的办法数之和;若不充足,办法总数就只能承袭吃前(i-1)道菜的办法总数。依次递推,在最后,我们只要输出(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;
    }
    
  • 相关阅读:
    Jetbrains IDE 中 compass sass 设置
    std::shared_ptr<void>的工作原理
    分辨率、DPI、PPI和屏幕尺寸,你都知道是啥么?
    《富爸爸,穷爸爸》阅读笔记
    [LeetCode] Interleaving String
    一致性哈希学习
    《精通正则表达式》笔记 --- “验证”Email格式
    字符串匹配算法
    [奇淫怪巧] 利用正则表达式判断素数
    《精通正则表达式》笔记 --- 选择引号内的文字
  • 原文地址:https://www.cnblogs.com/sxqn/p/13973873.html
Copyright © 2020-2023  润新知