POJ_2718_The smallest difference_DFS,剪枝

好好努力,上海加油。


题意:

给最少2个,最多10个数字,要求由这些数字拼起来组成两个数,没有前缀零,问所有合法组成的两个数中,差值最小是多少?



Input

The first line of input contains the number of cases to follow. For each case, there is one line of input containing at least two but no more than 10 decimal digits. (The decimal digits are 0, 1, ..., 9.) No digit appears more than once in one line of the input. The digits will appear in increasing order, separated by exactly one blank space.

Output

For each test case, write on a single line the smallest absolute difference of two integers that can be written from the given digits as described by the rules above.


两个数尽量等长差值肯定相对较小,所以就遍历n!种排列方式,从中间分开,算差值,更新答案。

算下操作数没多少,10!才3*10^6级别,但是还是超时了。

剪枝:当当前组成的第二个数(此时还没组完),即使最大且比第一个数小时,差值仍然大于已有答案;

           或当前组成的第二个数(此时还没组完),即使最小且比第一个数大时,差值仍然大于已有答案。

这两种情况不必继续搜索。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxl 30
#define mxn 20
#define inf 0x3f3f3f3f
int a[mxn],cnt;
int ans;
int poww[]={1,10,100,1000,10000};
bool isdigit(char in){
	return in>='0'&&in<='9';
}
int iabs(int in){
	return in<0 ? -in : in;
}
void dfs(int loc,int numa,int numb,int flag){
	int tema,temb;
	if(loc==cnt)
		ans=min(ans,iabs(numa-numb));
	if(loc-1>=cnt/2){
		tema=numb*poww[cnt-loc];
		temb=(numb+1)*poww[cnt-loc]-1;
		if(tema>=numa&&tema-numa>=ans)	return;
		if(temb<=numa&&numa-temb>=ans)	return;
	}
	for(int i=0;i<cnt;++i)	if(!(flag&(1<<i))){
		if(!loc&&cnt>3&&!a[i])	continue;
		if(loc==cnt/2&&cnt!=2&&!a[i])	continue;
		tema=numa,temb=numb;
		if(loc>=cnt/2)	temb=temb*10+a[i];
		else	tema=tema*10+a[i];
		dfs(loc+1,tema,temb,flag|(1<<i));
	}
}
int main(){
	int cs;
	scanf("%d",&cs);
	getchar();
	while(cs--){
		ans=inf;
		cnt=0;
		char eat;
		while((eat=getchar())!='\n')	if(isdigit(eat))
			a[cnt++]=eat-'0';
		dfs(0,0,0,0);
		printf("%d\n",ans);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值