PKU Shredding Company(蛋疼的搜索)

9 篇文章 0 订阅

搜索做了这么多,还是个渣,哎,真受不了。。。。。。

题目大意:

给你一个和值。然后给你一串数字,看你如果切割组合使得组合起来的数字最接近和值(但是必须小于等于给定的和值)。输出你组合出来的数的和,再输出组合后的数字序列。如果能够组合成多个符合要求的序列输出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;
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值