搜索做了这么多,还是个渣,哎,真受不了。。。。。。
题目大意:
给你一个和值。然后给你一串数字,看你如果切割组合使得组合起来的数字最接近和值(但是必须小于等于给定的和值)。输出你组合出来的数的和,再输出组合后的数字序列。如果能够组合成多个符合要求的序列输出rejected,如果找不到这样的组合(组合起来的 数字序列加起来全都大于给定的和值),那么输出error。
解题思路: 利用搜索里面的标记数组这次作为一个虚拟的挡板数组在一串数字中。比如这样1/2/3/4,那么如果数字的长度是4的话,最多能够分割3次。vis数组很自然的储存每个位置是否有挡板。
这道题目没有什么别的,就是情况比较多。那么要怎样去遍历所有的分割情况呢?在搜索的过程中,我们先把数字的每一位都分开,计算分开数字之后的和值。之后回溯,从最后一位的挡板开始,把挡板依次向后移动,如果移动到的当前位置能够放置挡板那么就再次放置挡板,对该位置的vis数组元素置1,否则继续向后移动放置,直到挡板不能移动位置。以每一位的挡板为搜索起点再继续进行深搜,放置,移动工作。每一次到挡板不能再放置的时候,或者放置的数量已经到达上限的时候,求和一次。
例如:
1/2/3/4--->1/2/34-->1/23/4-->1/234---->12/3/4--->12/34----123/4----->1234
求和的工作就不多说了,自己算一算就会明白代码是什么意思了。
代码如下:
//Shredding Company //
//题目链接:http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1004&ojid=1&cid=5201&hide=0
#include<stdio.h>
#include<string.h>
int SUM;
bool vis[20];
int sign;
int result[20];
int num[20];
int min=99999999;
int len;
int n;
int temp[20];
char shredder[11];
void add()
{
int k=0;
int d,he=0;
int i,j;
d=num[1];
for(i=1;i<=len-1;i++)
if(vis[i])
{
he+=d;
result[++k]=d;
d=num[i+1];
}
else
d=d*10+num[i+1];
result[++k]=d;
he+=d;
if(he<=SUM)
{
if(SUM-he<min)
{
min=SUM-he;
sign=1;
for(j=1;j<=k;j++)
temp[j]=result[j];
temp[0]=k;
}
else
if(SUM-he==min)
sign=2;
}
}
void dfs(int k)
{
if(k>n){add();return;}
vis[k]=1;
dfs(k+1);
vis[k]=0;
dfs(k+1);
}
int main()
{
int i,j,k;
while(scanf("%d",&SUM)!=EOF)
{
memset(vis,0,sizeof(vis));
sign=0;
min=99999999;
scanf("%s",shredder);
len=strlen(shredder);
n=len-1;
if(SUM==0&&(shredder[0]-48)==0)
break;
for(i=1;i<=len;i++)
num[i]=shredder[i-1]-48;
dfs(1);
if(min==99999999)
printf("error");
else
{
if(sign>1)
printf("rejected");
else
{
printf("%d",SUM-min);
for(j=1;j<=temp[0];j++)
printf(" %d",temp[j]);
}
}
printf("\n");
}
return 0;
}