ACM 124. [NOI1996]添加号(高精度+dp)

124. [NOI1996]添加号

★☆   输入文件: exam4.in   输出文件: exam4.out    简单对比
时间限制:2 s   内存限制:128 MB

【问题描述】
     有一个由数字 1 , 2 , ... , 9 组成的数字串(长度不超过 200 ),问如何将 M(M<=20) 个加号 ("+") 插入到这个数字串中,使所形成的算术表达式的值最小。请编一个程序解决这个问题。 注意: 加号不能加在数字串的最前面或最末尾,也不应有两个或两个以上的加号相邻。 M 保证小于数字串的长度。 例如:数字串 79846 ,若需要加入两个加号,则最佳方案为 79+8+46 ,算术表达式的值 133 。

【输入格式】 
     数字串在输入文件的第一行行首(数字串中间无空格且不折行),M的值在输入文件的第二行行首。

【输出格式】 
     输出所求得的最小和的精确值。

【输入输出样例】
 
输入: 
exam4.in
82363983742
3

输出:
exam4.out
2170


高精度+dp

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define INF 999999999999LL
#define MAX_N 250

typedef long long ll;

char text[MAX_N];
int k;

class BigInt
{
public:
	int dat[MAX_N];
	int len;
public:
	BigInt()
	{
		dat[0]=0;
		len=1;
	}
	BigInt(const char *str)
	{
		int len=strlen(str);

		for(int i=0;i<len;i++)
		{
			dat[i]=str[len-i-1]-'0';
		}
		this->len=len;
	}
	BigInt operator = (const BigInt &b)
	{
		memcpy(dat,b.dat,sizeof(dat));
		len=b.len;

		return b;
	}
	void Print()
	{
		for(int i=len-1;i>=0;i--)
		{
			cout<<dat[i];
		}
		cout<<endl;
	}
};

BigInt operator + (const BigInt &a,const BigInt &b)
{
	BigInt c("0");

	int len=max(a.len,b.len);
	memset(c.dat,0,sizeof(c.dat));
	for(int i=0;i<len;i++)
	{
		if(i<a.len)
			c.dat[i]+=a.dat[i];
		if(i<b.len)
			c.dat[i]+=b.dat[i];
	}
	for(int i=0;i<len;i++)
	{
		c.dat[i+1]+=c.dat[i]/10;
		c.dat[i]%=10;
	}
	if(c.dat[len]) c.len=len+1;
	else c.len=len;

	return c;
}


bool operator < (const BigInt &a,const BigInt &b)
{
	if(a.len!=b.len)
	{
		return a.len<b.len;
	}

	for(int i=a.len-1;i>=0;i--)
	{
		if(a.dat[i]!=b.dat[i])
			return a.dat[i]<b.dat[i];
	}

	return false;
}

BigInt d[MAX_N][MAX_N];
bool bd[MAX_N][MAX_N];
char tt[MAX_N];

BigInt GetNum(int s,int t)
{
	int len=0;
	for(int i=0;i<=t-s;i++)
	{
		tt[len++]=text[i+s];
	}
	tt[len]=0;

	return BigInt(tt);
}

BigInt dp(int t,int k)
{
	BigInt minx("0");
	minx.len=205;

	if(bd[t][k]) return d[t][k];
	if(k==0)
	{
		bd[t][k]=true;
		return d[t][0]=GetNum(0,t);
	}
	if(k>=t+1)
	{
		bd[t][k]=true;
		return d[t][k]=minx;
	}

	for(int i=0;i<t;i++)
	{
		BigInt num=GetNum(i+1,t)+dp(i,k-1);

		if(num<minx)
		{
			minx=num;
		}
	}
	bd[t][k]=true;
	return d[t][k]=minx;
}

int main()
{
	freopen("exam4.in","r",stdin);
	freopen("exam4.out","w",stdout);
	cin>>text;
	cin>>k;

	BigInt bint=dp(strlen(text)-1,k);
	//BigInt bint("6666");
//	bint=bint+bint;
	bint.Print();

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值