POJ1416 DFS+剪枝

[题目大意]:
     公司现在要发明一种新的碎纸机,要求新的碎纸机能够把纸条上的数字切成最接近而不超过target值。比如,target的值是50,而纸条上的数字是12346,应该把数字切成四部分,分别是1、2、34、6。因为这样所得到的和43 (= 1 + 2 + 34 + 6) 是所有可能中最接近而不超过50的。(比如1, 23, 4, 和6 就不可以,因为它们的和不如43接近50,而12, 34, 6也不可以,因为它们的和超过50了。碎纸还有以下三个要求:

1、如果target的值等于纸条上的值,则不能切。
2、如果没有办法把纸条上的数字切成小于target,则输出error。如target是1而纸条上的数字是123,则无论你如何切得到的和都比1大。
3、如果有超过一种以上的切法得到最佳值,则输出rejected。如target为15,纸条上的数字是111,则有以下两种切法11、1或者1、11.
你的任务是编写程序对数字进行划分以达到最佳值。

[输入]
   包含多组测试数据,每组测试数据一行,包行两个数,分别是target和纸条上的数字,两者之间用空格隔开。最后用0 0表示结束。注意,在切数过程中,0123是不合法的。每个数字不超过6位。
[输出]:
   每个测试数据输出一个结果,分别为以下三种情况a、rejected   b、error   c、sum part1 part2 …….第三种情况中的sum代表你所能得到的最接近值,part1等是具体切出来的数字,按照原来在纸条上的顺序出现。数字之间用空格分开。每行首尾不能有多余的空格。

[样例]
Sample Input
50 12346
376 144139
927438 927438
18 3312
9 3142
25 1299
111 33333
103 862150
6 1104
0 0

Sample Output
43 1 2 34 6
283 144 139
927438 927438
18 3 3 12
error
21 1 2 9 9
rejected
103 86 2 15 0
rejected

解题 分析:

1.使用DFS(深度优先搜索算法),搜索符合条件的解,搜索过程中要注意保存搜索到的解。

2.搜索过程中,判断当前记录值是否大于目标值,若大于则结束搜索,返回上一层。搜索过程中构建的搜索树是有序的。

代码如下:

import java.util.*;
class Main
{
private int target; //输入的目标值
private char num[]; //输入的数,用数组储存,便于搜索操作
private int max; //搜索得到的最大值
private StringBuilder sb; //记录当前搜索得到的结果,字符串容器,Java中封装的,方便操作数据。
private StringBuilder result;
private boolean check; //用于条件的判断
public Main(int target,char[] num) //构造函数
{
this.target=target;
this.num=num;
max=0;
sb=new StringBuilder("");
result=new StringBuilder("");
}
public boolean getCheck()
{
return check;
}
public int getMax()
{
return max;
}
public String getResult()
{
return result.toString();
}
private boolean isOk() //对输入的数据进行判断,计算每个数值相加之后的和是否大于目标值。每个数值相加的和为最小值
{
int sum=0;
for(int i=0;i<num.length;i++)
{
sum+=num[i]-'0';
}
if (sum>target) 
{
return false;
}
else
return true;
}
public void dfs(int startIndex,int sumTotal) // 搜索算法的主体,startIndex表示从该下标处进行搜索,sumTotal记录当前搜索得到的总和
{
int i,t=0; //t,该次搜索所得到的值
if(startIndex==num.length) //表示搜索结束
{
if(sumTotal==max)
{
check=false;
}else if (sumTotal>max)
{
check=true;
max=sumTotal;
result=sb;
}


}
for(i=1;i<num.length-startIndex+1;i++)//遍历到从startIndex开始遍历时,最多的可能结果为num.length-startIndex个
   {
t=t*10;
t+=num[startIndex+i-1]-'0'; //注意字符转换成int型的小技巧
if(t+sumTotal>target)
return;
StringBuilder tt=new StringBuilder(sb);
sb.append(Integer.toString(t)).append(" ");
dfs(startIndex+i,sumTotal+t); //满足条件之后继续向下搜索
sb=tt; //从上一层返回之后,继续向前回溯。tt记录sb上一层的值
}
}
public static void main(String[] args) 
{
Scanner sc=new Scanner(System.in);
while(sc.hasNext())
{
int target=sc.nextInt();
char num[]=sc.next().toCharArray(); //将字符串转成字符数组
if(target==0)
break;
Main m=new Main(target,num);
if(!m.isOk())
System.out.println("error");
else
{
m.dfs(0,0); //从数组下标0开始搜索
if(!m.getCheck())
System.out.println("rejected");
else
{
System.out.println(m.getMax()+" ");
System.out.println(m.getResult());
}
}
}
}
}

总结:

1.要注意分析问题,尤其是设计算法的时候。该问题中,经过简单分析即可得到每一次搜索时需要搜索的次数,与未搜索到的元素的个数相同。

2.利用回溯法解题的过程。利用回溯法时,要注意向上回溯的条件,如何保存条件,以及递归的结束标志。

3.要注意利用已知的条件去判断,加快搜索过程,减少不必要的搜索。

利用DFS的框架如下:

void backtrack(int)
{
if(t>n)output(x);
else
for(int i=f(n,t);i<=g(n,t);i++){
x[t]=h(i);
if(constraint(t)&&bound(t))backtrack(t+1);
}
}

以后还是要多练习,多联系才能掌握。


.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值