P2089 烤鸡题解

题目

猪猪Hanke特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke吃鸡很特别,为什么特别呢?因为他有10种配料(芥末、孜然等),每种配料可以放1到3克,任意烤鸡的美味程度为所有配料质量之和。 

现在, Hanke想要知道,如果给你一个美味程度n ,请输出这10种配料的所有搭配方案。

输入输出格式

输入格式

一个正整数n,表示美味程度。

输出格式

第一行,方案总数。

第二行至结束,10个数,表示每种配料所放的质量,按字典序排列。

如果没有符合要求的方法,就只要在第一行输出一个0。

输入输出样例

输入样例

11

输出样例

10
1 1 1 1 1 1 1 1 1 2 
1 1 1 1 1 1 1 1 2 1 
1 1 1 1 1 1 1 2 1 1 
1 1 1 1 1 1 2 1 1 1 
1 1 1 1 1 2 1 1 1 1 
1 1 1 1 2 1 1 1 1 1 
1 1 1 2 1 1 1 1 1 1 
1 1 2 1 1 1 1 1 1 1 
1 2 1 1 1 1 1 1 1 1 
2 1 1 1 1 1 1 1 1 1 

代码1

这个题目美味程度最多只能达到3*10=30,至少是10。可以直接使用10层for循环,再加一个if判断,就能找到符合条件的情况。题目中字典序输出的意思就是前面的数越小,这个方案就排在前面。因为10层for循环蕴含了这一性质,所以字典序对解法没有影响。

这里使用的另外一种用法:构造语句。写下rep(a,1,3)时,编译器会自动在代码中把它替换成for(int a=1;a<=3;a++)。但要注意的是,宏定义只会做简单的字符串替换。如果定义了#define prod(a,b) a*b,然后又写了prod(a+b,c),编译器将会把它理解成a+b*c,并非想要的(a+b)*c。一个解决方案是定义宏时勤加括号,如#define prod(a,b) (a)*(b),这样就可以避免出现运算优先级的bug。

#include<iostream>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int main(){
	int n,ans=0,cnt=10;
	cin>>n;
	rep(a,1,3) rep(b,1,3) rep(c,1,3) rep(d,1,3) rep(e,1,3) rep(f,1,3)
	    rep(g,1,3) rep(h,1,3) rep(i,1,3) rep(j,1,3)
	        if(a+b+c+d+e+f+g+h+i+j==n){
		        ans++;
	        }
	        cout<<ans<<endl;
	rep(a,1,3) rep(b,1,3) rep(c,1,3) rep(d,1,3) rep(e,1,3) rep(f,1,3)
	    rep(g,1,3) rep(h,1,3) rep(i,1,3) rep(j,1,3)
	        if(a+b+c+d+e+f+g+h+i+j==n){
		        cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<e<<" "<<f<<" "<<g<<" "<<h<<" "<<i<<" "<<j<<endl;
	        }
	return 0;
}

代码2

这个题目还可以再优化,如果a,b,c,d,e加起来已经超过n,那么显然f,g,h,i,j就没有继续尝试枚举的必要了。针对这个问题,对这道题目进行枚举剪枝——限定每个变量的范围。比如e,在满足1<=e<=3的同时,还能做到一个更好的估计:n-15-a-b-c-d<=e<=n-5-a-b-c-d。这个不等式左侧是假设后面都取3,那么e至少这么大;右侧是假设会面都取1,那么3最大这么大。同时使用数组li来记录符合要求的答案,这样就不需要枚举两次大循环,又进一步加快了速度。

#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=max(1,a);i<=min(3,b);i++)
int li[60000][10];
int main(){
	int n,ans=0,cnt=10;
	cin>>n;
	rep(a,n-27,n-9)
	   rep(b,n-24-a,n-8-a)
	      rep(c,n-21-a-b,n-7-a-b)
	         rep(d,n-18-a-b-c,n-6-a-b-c)
	            rep(e,n-15-a-b-c-d,n-5-a-b-c-d)
	               rep(f,n-12-a-b-c-d-e,n-4-a-b-c-d-e)
	                  rep(g,n-9-a-b-c-d-e-f,n-3-a-b-c-d-e-f)
	                     rep(h,n-6-a-b-c-d-e-f-g,n-2-a-b-c-d-e-f-g)
	                        rep(i,n-3-a-b-c-d-e-f-g-h,n-1-a-b-c-d-e-f-g-h)
	                           rep(j,n-a-b-c-d-e-f-g-h-i,n-a-b-c-d-e-f-g-h-i){
	                           	li[ans][0]=a;li[ans][1]=b;li[ans][2]=c;
	                           	li[ans][3]=d;li[ans][4]=e;li[ans][5]=f;
	                           	li[ans][6]=g;li[ans][7]=h;li[ans][8]=i;
	                           	li[ans][9]=j;
	                           	ans++;
							   }
	cout<<ans<<endl;
	for(int i=0;i<ans;i++){
		for(int j=0;j<10;j++){
			cout<<li[i][j]<<" ";
		}
		cout<<endl;
	}			
	return 0;			   
}
  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值