亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

動態規劃——看似dp的貪心問題最大乘積(藍橋杯試題集)

標簽:
算法

题目链接:


http://lx.lanqiao.cn/problem.page?gpid=T136


问题描述
  对于n个数,从中取出m个数,如何取使得这m个数的乘积最大呢?
输入格式
  第一行一个数表示数据组数
  每组输入数据共2行:
  第1行给出总共的数字的个数n和要取的数的个数m,1<=n<=m<=15,
  第2行依次给出这n个数,其中每个数字的范围满足:a[i]的绝对值小于等于4。
输出格式
  每组数据输出1行,为最大的乘积。
样例输入
1
5 5
1 2 3 4 2
样例输出
48 


一:首先要分离正负,两个负值乘积为正。做这道题时让我想起了按键盘http://blog.csdn.net/sm9sun/article/details/53241628

 与其一样的是,按键盘保留大小写两种状态,那么本题也要保留正负最大值两种状态

二:类似于01背包,我们把m当作容量,每个数的体积都是1

这样一来每个数都面临取或者不取两种状态,当我们遍历到第i个物品时,我们要保留在i个物品中取j个物品的最大正负值即可



#include<stdio.h>#include<math.h>double fmax(double a,double b){	return a>b?a:b;}double fmin(double a,double b){	return a<b?a:b;}int main(){	double a[20];double fdp[20][20][20];double dp[20][20][20];	int m,n,i,j,k,t;	scanf("%d",&t);	while(t--)	{		scanf("%d%d",&n,&m);for(i=1;i<=n;i++)		scanf("%lf",&a[i]);for(i=0;i<=n;i++)		for(j=0;j<=m;j++)	for(k=0;k<=j;k++)	{	dp[i][j][k]=1;		fdp[i][j][k]=1;	}	fdp[0][1][1]=dp[0][1][1]=a[1];	for(i=1;i<=n;i++)                   //遍历n个数{for(j=1;j<=m&&j<=i;j++)             //m为容量,从i个数中取j个数{        	for(k=1;k<=j;k++)           //k遍历当我容量上限为j时取不同个数的最大值,这里与01背包不同,取值必须达到m容量,不能小于        	{                           //所以每一个k都要记录下来if(a[i]>0){dp[i][j][k]=fmax(dp[i-1][j][k],dp[i-1][j-1][k-1]*a[i]);fdp[i][j][k]=fmin(fdp[i-1][j][k],fdp[i-1][j-1][k-1]*a[i]);}else{dp[i][j][k]=fmax(dp[i-1][j][k],fdp[i-1][j-1][k-1]*a[i]);fdp[i][j][k]=fmin(fdp[i-1][j][k],dp[i-1][j-1][k-1]*a[i]);}			// printf("%.0lf,%.0lf ",dp[i][j][k],fdp[i][j][k]);}//printf("---");}//printf("\n");}printf("%.0lf\n",dp[n][m][m]);}return 0;}


用dp思想的确可以解决这道题,不过后来看了网上的答案,发现其实还有更简单的方法,用贪心~


我们将正负数分组排序后,依次选取两个最大正值乘积,两个最大负值乘积即可~

注意,如果m为奇数时要再乘一个正数。



#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int main(){int t, n, m;int num[20];scanf("%d", &t);while(t--){scanf("%d %d", &n, &m);for(int i = 0; i < n; i++)scanf("%d", &num[i]);sort(num, num+n);int i, j, a, b;i = j = 0;long long ans = 1;while(m){a = num[i]*num[i+1];b = num[n-j-1]*num[n-j-2];if(a>=b && m>=2){ans*=a;i+=2;m-=2;}else{ans*=num[n-j-1];j++;m--;}}printf("%lld\n", ans);}return 0;}

所以说,也不能盲目的运用dp,有一些问题还是可以用贪心解决的。


點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消