n点游戏 [PSA]  EOlymp - 44 DP JAVA

92 篇文章 0 订阅
75 篇文章 0 订阅

F - n点游戏 [PSA]

 EOlymp - 44 

24点游戏是非常经典而简单的小游戏,从一堆扑克牌中抽取4张,向其中添加运算符号并使其运行结果恰等于24,这叫作24点游戏。

现在我们不再是组合24,而是组合出给定的数字n,但要求只可以利用任意多个数字1,并且运算只有加法、乘法和括号。对于给定的数字N,最少需要几个1可以完成

数据输入

输入一个数字N( 1≤N≤5000)

数据输出

输出一个整数,表示仅用加号,乘号和括号能组成等于N所需最少的1的个数

样例1

输入样例

7

输出样例

6

提示

7=(1+1)*(1+1+1)+1

样例2

输入样例

27

输出样例

9

提示

27=(1+1+1)*(1+1+1)*(1+1+1)

很明显,这个一个动态规划的题

想要获得一个数的最优解,就要获得组成这个数的最优解。

1:1  2:2  3:3  4:4

5:5  6:5  7:6   8:6

9:6  ... 12:7  13:8 

26:10  27:9

设f(n)为数n的最优解

可以发现,质数=f(n-1)+1 合数= f(其组成的原子数) 之和。这里的原子数就是不可再拆分的数==质数。

结合贪心,可以发现,原子数的大小应当尽量的大。(初始值使temp=sqrt(n))即应当是f(9)=f(3)+f(3) 而不是f(2)+f(2)+f(2)+f(2)+1

JAVA版写了一个递归,思想同上,自顶向下的思路,因此要加一个记忆数组,防止出现重复计算。(空间换时间)

需要注意如果N由X * Y组成,那么还需要判断一下f(N-1)+1与f(X)+f(Y)的大小。

import java.util.Scanner;
public class Main {
	static int remb[] = new int[5005];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		remb[1]=1;
		remb[2]=2;
		remb[3]=3;
		System.out.println(f(n));
	}
	static int f(int n) {
		if(remb[n]!=0)
			return remb[n];
		int temp =(int)(Math.pow(n, 0.5));
		while(temp!=1) {
			if(n%temp==0) {
				remb[n] =  f(temp)+f(n/temp);
				break;
			}
			temp--;
		}
		if(temp==1) {
			remb[n] = f(n-1)+1;
		}else
			remb[n] = Math.min((f(n-1)+1),remb[n]);	//重要 有个别测试点需要的
		return remb[n];
	}
}

也可以是自底向上的思想。

一般的,自顶向下的思维是我们最容易想到的,但需要加记忆数组,代码相对多一点。

而自底向上的思想需要绕一下弯,一般代码较少,更简洁。

两者的运行效率一般都差不多

C++版的自底向上:

#include <cstdio>
#include <algorithm>
#define MAXN 5007
using std::min;


int main(void)
{
     int i,j,N;
     int dp[MAXN];
     scanf("%d",&N);
     dp[1]=1;
     for(i=2;i<=N;i++)
     {
         dp[i]=dp[i-1]+1;
         for(j=2;j*j<=i;j++)
         {
             if(i%j==0)
             {
                 dp[i]=min(dp[i],dp[i/j]+dp[j]);
             }
         }
     }

     printf("%d\n",dp[N]);

     return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值