1. 程式人生 > >天平 數學+DP

天平 數學+DP

long pan ostream i++ stdout clu n) lan nbsp

【問題描述】
大牛最近正在為自己的體重而苦惱,他想稱量自己的體重。於是,他找來一個天平與許
多砝碼。
砝碼的重量均是 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\n",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\n",min(f[yu][0],f[yu][1]+1));

	return 0;
}

天平 數學+DP