HDU 1258

来源:互联网 发布:redis 数据有效期 编辑:程序博客网 时间:2024/06/10 17:24

这是我没有经过讨论写出来的,思维比较狭隘些吧,因为有人比我快很多AC了,所以希望看过我的代码的高手们给我提些建议和意见~谢谢咯~如果有比较简单高效的方法也请留言~~欢迎欢迎~~微笑

/*HDU 1258 SUM IT UPSample Input4 6 4 3 2 2 1 15 3 2 1 1400 12 50 50 50 50 50 50 25 25 25 25 25 250 0Sample OutputSums of 4:43+12+22+1+1Sums of 5:NONESums of 400:50+50+50+50+50+50+25+25+25+2550+50+50+50+50+25+25+25+25+25+25大致就是将给的总和total用给的数列里的数用和式计算出来将所有的和式都列出来,然后列式的要求是数字从大到小总的思路用了DFS,把大问题分解成了小问题。就是把一个t分成一个m+t然后递归求t的和式,打印出来,再找下一个m。。Q1:出了如4 3 2 2 1 1的数列,当用到最后一个1(p=5)的时候,明明只用了一个1,但是由于visit[1]在取到num[4]的时候就输出一下,之后又见到num[4]的时候就又输一遍1所以就出问题了。然后解决方法是:判断当前的num[i]和num[i+1]是否相等,如果相等的话,就continue,直到走到了相同数的最后一个,然后找visit[num[i]]打印。Q2:如果有数列数相同的话,可能会坐标不同数字一样而重新搜过,并且重复打印。但是如果在递归的时候就直接判断是否数字一样,然后不进行这个数的搜索的话,又会有4=2+2,搜不到这种情况,所以不能这么简单地把数字相等的都不进行递归。解决方法:又设了一个数组remember[],进行记忆,打印前对比一下visit[]和remember[],如果两个完全一样的话,就不再输出。*/#include<stdio.h>#include<string.h>int N;int num[101];int visit[1000]={0};int remember[1000]={0};int DFS(int t,int n,int p,int m){int re=0;int sign=0;int i,j;if(t==m){visit[m]++;for(i=0;i<=p;i++){if(visit[num[i]]==remember[num[i]]){sign=1;}else{sign=0;break;}}if(sign){visit[m]--;return 0;}for(i=0;i<=p;i++){if(num[i+1]==num[i]&&(i+1)<=p)continue;for(j=0;j<visit[num[i]];j++){printf("%d",num[i]);if(!(i==p&&j==visit[num[i]]-1))printf("+");}}printf("\n");for(i=0;i<=p;i++){remember[num[i]]=visit[num[i]];}visit[m]--;return 1;}t=t-m;if(p+1>=n||t<0){return 0;}visit[m]++;for(i=p;i<n;i++){//if(num[i+1]==num[i]&&(i+1)<n)//continue;re+=DFS(t,n,i+1,num[i+1]);}visit[m]--;return re;}int main(){int t,p,re=0;int i,j;while(1){scanf("%d %d",&t,&N);if(N==0)return 1;memset(num,0,100);for(i=0;i<N;i++)scanf("%d",&num[i]);p=0;printf("Sums of %d:\n",t);memset(visit,0,1000);memset(remember,0,1000);for(i=0;i<N;i++){if(num[i]==num[i-1]&&(i-1)>=0)continue;re+=DFS(t,N,i,num[i]);}if(!re)printf("NONE\n");re=0;}}



原创粉丝点击