zoj Additive equations

来源:互联网 发布:淘宝网男士高领打底衫 编辑:程序博客网 时间:2024/05/20 21:48

题目大意:

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

解题思路:

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


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


#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]);elseprintf("+%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_JUDGEfreopen("f:\\in.txt","r",stdin);#endifint 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]);elseprintf("%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_JUDGEfreopen("f:\\in.txt","r",stdin);#endifint 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");elseprintf("\n");}return 0;}


原创粉丝点击