• 洛谷 P1164:小A点菜(DP/DFS)


    题目背景

    uim神犇拿到了uoira(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种。

    uim指着墙上的价目表(太低级了没有菜单),说:“随便点”。

    题目描述

    不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩 MM 元 (M le 10000)(M≤10000) 。

    餐馆虽低端,但是菜品种类不少,有 NN 种 (N le 100)(N≤100) ,第 ii 种卖 a_iai​ 元 (a_i le 1000)(ai​≤1000) 。由于是很低端的餐馆,所以每种菜只有一份。

    小A奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim身上所有钱花完。他想知道有多少种点菜方法。

    由于小A肚子太饿,所以最多只能等待 11 秒。

    输入输出格式

    输入格式:

    第一行是两个数字,表示 N和 M 。

    第二行起 N个正数 ai​ (可以有相同的数字,每个数字均在 10001000 以内)。

    输出格式:

    一个正整数,表示点菜方案数,保证答案的范围在 int 之内。

    输入输出样例

    输入样例#1: 复制

    4 4
    1 1 2 2
    

    输出样例#1: 复制

    3

    思路

    • DP:好像是01背包的变形(看到好多大佬都是这样说)。用dp数组来记录拿到总价值数为j时的方案数(我是这样理解的,把dp过程打表出来好像也是这样),最后输出dp[m]的方案数就行了。下面是我打的dp过程时的表(数据是样例中的数据)

    • DFS:暴力似乎能解决一切问题(在时间够的情况下)。直接枚举所有的情况,加上剪枝就可以了(这个题加上剪枝并没有减少什么时间,难道是剪枝的姿势不对?)

    AC代码

    DP:

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <limits.h>
    #include <map>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <set>
    #include <string>
    #define ll long long
    #define ms(a) memset(a,0,sizeof(a))
    #define pi acos(-1.0)
    #define INF 0x3f3f3f3f
    const double E=exp(1);
    const int maxn=1e3+10;
    using namespace std;
    int a[maxn];
    int dp[maxn];//记录拿到总价值为j的物品的方案数
    int main(int argc, char const *argv[])
    {
    	ios::sync_with_stdio(false);
    	int n,m;
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)
    		cin>>a[i];
    	ms(dp);
    	dp[0]=1;
    	for(int i=1;i<=n;i++)
    	{
    		// cout<<"取到第"<<i<<"个物品时"<<endl;
    		for(int j=m;j>=a[i];j--)
    		{
    			dp[j]+=dp[j-a[i]];
    			// cout<<"i:"<<i<<"	"<<"j:"<<j<<"	"<<"a[i]:"<<a[i]<<"	"<<"dp[j]:"<<dp[j]<<endl;
    		}		
    	}
    	cout<<dp[m]<<endl;
    	return 0;
    }
    

    DFS:

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <limits.h>
    #include <map>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <set>
    #include <string>
    #define ll long long
    #define ms(a) memset(a,0,sizeof(a))
    #define pi acos(-1.0)
    #define INF 0x3f3f3f3f
    const double E=exp(1);
    const int maxn=1e6+10;
    using namespace std;
    int n,m;
    int ans;
    int a[maxn];
    int vis[maxn];//记录这种菜是否选过
    void dfs(int x,int y)//x表示选到第几个菜,y表示当前菜的总价值
    {
    	if(y>m)
    		return ;
    	if(y==m)
    	{
    		ans++;
    		return ;
    	}
    	// 从当前所选的菜的位置向后遍历
    	for(int i=x+1;i<=n;i++)
    	{
    		// 如果当前菜没有被选
    		if(vis[i]==0)
    		{
    			vis[i]=1;
    			dfs(i,y+a[i]);
    			// 回溯
    			vis[i]=0;
    		}
    	}
    	
    }
    int main(int argc, char const *argv[])
    {
    	ios::sync_with_stdio(false);
    	cin>>n>>m;
    	ms(vis);
    	ms(a);
    	for(int i=1;i<=n;i++)
    		cin>>a[i];
    	ans=0;
    	dfs(0,0);
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    泛型编程 --迭代器
    cpp输入输出加速
    算法训练 加法运算(指针的一个测试)
    蓝桥杯-基础练习-字母图形
    蓝桥杯-基础练习-特殊回文数
    win10下稍微美观下Git
    mysql8.0以上版本注册驱动并建立数据库的连接公共代码
    idea使用的一些问题解决记录
    单链表逆转(递归指针实现)
    increment/decrement/dereference操作符
  • 原文地址:https://www.cnblogs.com/Friends-A/p/10324405.html
Copyright © 2020-2023  润新知