zoj Additive equations

9 篇文章 0 订阅

题目大意:

给你一个数字序列里面的数字都是不同的,让你找出不同组合的加法式,但是等式中的加数和结果都必须在给定的数字序列中(已知数字序列中的数字不会重复)。

解题思路:

题目要求输出的时候首先按式子的长度排序输出,之后如果式子长度相同,那么按照第一个加数在序列中的顺序进行排序输出。


先贴个我自己写的代码吧,是一堆垃圾,琢磨了好久还是没做出来,但是看了题解自后,觉得思想是完全相同的


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int max1,n;
int count1;
int num[50];
bool vis[50];
int result[50];
int t;
int sign=0;
int flag;
void dfs(int sum,int pos,int count)
{
	int i,j;
	if(sum<max1&&count==count1+1)
		return ;
	if(sum>max1||count>count1+1)
		return ;
	if(sum==max1&&count==count1+1)
	{
		for(j=0;j<t;j++)
			if(j==0)
				printf("%d",result[j]);
			else
			printf("+%d",result[j]);
		sign=1;
		flag=1;
		return ;
	}
	for(i=pos+1;i<=n;i++)
	{
		if(vis[i]==0&&num[i]<=max1)
		{
			sum+=num[i];
			vis[i]=1;
			result[t++]=num[i];
			count++;
			dfs(sum,i,count);
			result[--t]=0;
				++t;
			vis[t--]=0;
			count--;
			sum-=num[i];
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("f:\\in.txt","r",stdin);
#endif
	int i,j,k;
	int T;
	int d;
	scanf("%d",&T);
	while(T--)
	{
		t=0;
		scanf("%d",&n);
		for(i=1;i<=n;i++)
			scanf("%d",&num[i]);
		
		sort(num+1,num+1+n);
		flag=0;
		for(i=3,max1=num[i];i<=n;i++)
		{
			max1=num[i];
			for(count1=1,t=0;count1<=n-2;count1++) 
			{
				memset(result,0,sizeof(result));
				memset(vis,0,sizeof(vis));
				d=num[1];
				t=0;
				result[t++]=num[1];
				vis[1]=1;
				sign=0;
				dfs(d,0,1);
				if(sign==1)
					printf("=%d\n",max1);
			}
			if(sign==0&&flag==0)
				printf("Can't find any equations.\n");
		}
		printf("\n");
	}
	return 0;
}


这份代码一开始是想按照和值来搜索,以长度作为限制条件,比如,先搜等于3的,那么从长度为2的开始搜索。每次加一个数字判断是否超出我当前要搜索的和值,并且是否已经超出了所限制的长度条件。

过了样例之后,一直还是WA,然后也感觉自己写的很烂,输出等地方有很多漏洞,就没有再改

后来看了解题报告之后,发现有两点不同,第一个是处理输出,我想先存再输出,但是很复杂,还有一个就是我长度的控制总是出现问题,而且按照每个和值来搜索的话,每一个和值都要从长度2搜索到长度n-1,这样也会浪费很多时间。






后来想到,既然已经排序,那么我们就从第一个开始搜索,每次检查相加的和值是否小于这个数列中最大的那个数值,如果小于,那么证明有可能组合为一个等式,每次加上一个数之后,相应的长度都要剪1,假设我们现在搜索长度为2的等式,那么加了两个数的时候长度就变为0,可以开始输出工作。得到和值之后,例如 sum=1+2,那么我们要在2的后面去寻找是否有等于他们和值的数字,只要找到后面的数字有一个大于他们的和值为止。

如果找到那我们就输出,没有找到就退出。假设我们一开始找了1+2,但是发现数列中没有和3相等的数字,那么就把2换掉,去搜索后面的数字。这样的搜索方式,每次都是依次以序列中的数字为起点向后搜索,知道最后一个点为起点,那么就退出。而等式的长度又是一个大循环,将这些操作都包含在里面。搜索顺序的确定,自然也就方便的输出的顺序。



再说输出:

如果我现在找到了1+2,那么从2的位置开始,一直搜索到n-1,如果2位置后面的数字小于1+2的和值,那么它也许是答案,但是我们要进一步判断,如果2的位置后面的数字大于1+2的和值了,那么这个数字的后面以及它本身都不再是答案,可以退出。输出的时候从第一个已经被标记的数字开始输出,每次输出之后,和值sum都要减掉刚输出的数字,直到sum和最后一个要输出的加数相等时候,一起把最后一个加数和和值一起输出。



代码如下:

//题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1204
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int num[50];
bool vis[50];
int result[50];
int n;
int flag=0;
void dfs(int start,int len,int sum)
{
	int i,j,q;
	if(len==0)
	{
		for(i=start;i<n&&sum>=num[i];++i)
		{
			if(sum==num[i])
			{
				flag=1;
				for(j=0;j<=i;j++)
				{
					if(vis[j])
					{
						if(sum==num[j])
							printf("%d=%d\n",num[j],num[i]);
						else
							printf("%d+",num[j]);
						sum-=num[j];
					}
					//sum-=num[j];
				}
			}
		}
	}
	else
	{
		for(q=start;q<n;q++)
		{
			if(sum+num[q]<=num[n-1])
			{
			sum+=num[q];
			vis[q]=1;
			--len;
			dfs(q+1,len,sum);
			vis[q]=0;
			sum-=num[q];
			++len;
			}
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("f:\\in.txt","r",stdin);
#endif
	int i,j,k;
	int T;
	int d;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(i=0;i<n;i++)
			scanf("%d",&num[i]);
		sort(num,num+n);
		memset(vis,0,sizeof(vis));
		flag=0;
		for(j=2;j<=n-1;j++)
			dfs(0,j,0);
		if(!flag)
			printf("Can't find any equations.\n\n");
		else
			printf("\n");

	}
	return 0;

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值