天平 数学+DP

【问题描述】
大牛最近正在为自己的体重而苦恼,他想称量自己的体重。于是,他找来一个天平与许
多砝码。
砝码的重量均是 n 的幂次,n^1、n^2、n^3、n^4、n^5 的......大牛想知道至少要多少个
砝码才可以称出他的重量 m。注意砝码可以放左边,也可以放右边。
【输入格式】
第一行一个正整数 m,表示大牛的重量;
第二行一个正整数 n,表示砝码重量幂次的底;
【输出格式】
一个整数表示最少所需的砝码数。
【样例输入】
99
10
【样例输出】
2
【数据范围】
对于 30%的数据点,m <= 2^63 - 1
对于 100%的数据点,0 <= m <= 10^10000, 0 < n <= 10000


首先我们很容易想到把m化成n进制数来考虑。

所以我们先用高进度除法把m化成n进制数,然后因为可以放左右边,所以到了当前位,我们可以选择放x个砝码,也可以选择放n-x个砝码,然后下一位加1。

考虑到当前选择没有后效性,我们于是考虑在每一位上DP。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define ll long long
#define il inline
#define db double

#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

using namespace std;

int n;

char mm[100045];

int a[100045],b[100045];

int yushu[100045],yu;

int len;

bool flag;

il void get()
{
	int rest=a[0];
	int now=1;
	int cnt=0;
	while(now<=len-1)
		{
			rest=rest*10+a[now];
			if(rest>=n)
				{
					b[cnt++]=rest/n;
					rest=rest%n;
				}
			else b[cnt++]=0;
			now++;
		}

	yushu[++yu]=rest;

	for(int i=0;i<cnt/2;i++)
		swap(b[i],b[cnt-i-1]);

	while(b[cnt-1]==0)
		cnt--;

	for(int i=0;i<cnt/2;i++)
		swap(b[i],b[cnt-i-1]);

	if(cnt<=0)
		flag=1;

	for(int i=0;i<cnt;i++)
		a[i]=b[i];

	len=cnt;
}

ll f[100045][2];

int main()
{
	freopen("balance.in","r",stdin);
	freopen("balance.out","w",stdout);

	scanf("%s",mm);

	len=strlen(mm);
	for(int i=0;i<len;i++)
		a[i]=mm[i]-'0';

	cin>>n;

	if(n==1)
		{
			for(int i=0;i<len;i++)
				printf("%c",mm[i]);
			return 0;
		}

	while(flag==0)
		get();

	f[0][0]=0;
	f[0][1]=1;

	//for(int i=1;i<=yu;i++)
		//	printf("%d
",yushu[i]);
	//cout<<endl;		
	for(int i=1;i<=yu;i++)
		{
			f[i][0]=min(f[i-1][0]+yushu[i],f[i-1][1]+yushu[i]+1);//直接拿出
			f[i][1]=min(f[i-1][0]+n-yushu[i],f[i-1][1]+n-yushu[i]-1);//反向拿出
		}

	printf("%lld
",min(f[yu][0],f[yu][1]+1));

	return 0;
}
原文地址:https://www.cnblogs.com/gshdyjz/p/7700240.html