nyist-部分和问题

来源:互联网 发布:nginx自动跳转首页 编辑:程序博客网 时间:2024/06/08 11:04

部分和问题

时间限制:1000 ms  |  内存限制:65535 KB
难度:2
描述
给定整数a1、a2、.......an,判断是否可以从中选出若干数,使它们的和恰好为K。
输入
首先,n和k,n表示数的个数,k表示数的和。
接着一行n个数。
(1<=n<=20,保证不超int范围)
输出
如果和恰好可以为k,输出“YES”,并按输入顺序依次输出是由哪几个数的和组成,否则“NO”
样例输入
4 131 2 4 7
样例输出
YES2 4 7
来源
经典题目

这道题是水题?

我咋觉得一点也不水~~~~~

可能是我太水,我自己写的代码  发现了很多问题,结果都出现不了 下面我一点一点分析

#include<stdio.h>#include<string.h>bool flag;int a[30],b[30],sum;int n,k,j;void dfs(int x){    sum+=a[x];    if(sum==k)    {        flag=true;        return;    }    if(sum>k)    {        sum-=a[x];        return;    }    if(sum<k)    {        b[j++]=a[x];        dfs(x+1);    }}int main(){    while(scanf("%d%d",&n,&k)!=EOF)    {        j=0,sum=0;        memset(b,0,sizeof(b));        for(int i=0; i<=n; i++)        {            scanf("%d",&a[i]);        }        for(int i=0; i<=n; i++)        {            dfs(i);        }        if(flag)        {            printf("YES\n");            for(int i=0; a[i]!=0; i++)            {                printf("%d ",b[i]);            }            printf("\n");        }        else        {            printf("NO\n");        }    }}

这是我第一次的代码  都无法输出结果

递归都写错 了  几乎没有一点对的(初学见谅)

原先的思路是把数存进b【30】中  但是发现麻烦  不如直接判断这个数用没,没用表示0 用了表示1

而且这样写递归  不容易看对错

还有一个问题  我在递归里面没有用for循环,代替的在主函数里用了

(说说for循环的作用);如果没有for循环 那么我只是简单递归 这个数加不加  如样例   1 2 4 7  先1  接着递归 2 继续 4 还小于13  继续7 变成14  好了不满足条件

我返回  只有 1 2 4    根据代码 我继续返回 1 2  继续返回  1 最后没了  那就没答案了    

但是  我for循环加在主函数后  只是在  第一个数选择  1不行时选择  第一个数为2   选择时  中间不会跳过数字  如   4  17         1 7 3  10   这组样例  1开头不行  我7开头  递归3  不够 递归 10  多了  返回  再返回  最后又是无解

for在里面就没有这种情况

for(int i=pos;i<n;i++)    {          sum+=a[i];          visit[i]=1;          dfs(i+1);          sum-=a[i];          visit[i]=0;      }  

最后修改  成这样
#include <cstdio>#include <cstring>using namespace std;int a[30],visit[30],n,k,sum;bool flag;void dfs(int pos){    if(flag==true)        return ;    if(sum>k)    {        return;    }    if(sum==k)    {        flag=true;        return;    }    for(int i=pos; i<n; i++)    {        sum+=a[i];        visit[i]=1;        //printf("%d %d %d\n",pos,i,sum);        /*for(int k=0; k<n; k++)        {            printf("%d ",visit[k]);        }        printf("\n");*/        dfs(i+1);        if(!flag)        {            sum-=a[i];            visit[i]=0;        }    }}int main(){    int i;    while(scanf("%d%d",&n,&k)!=EOF)    {        for(i=0; i<n; i++)            scanf("%d",&a[i]);        memset(visit,0,sizeof(visit));        flag=false;        dfs(0);        if(!flag)            printf("NO\n");        else        {            printf("YES\n");            for(int j=0; j<n; j++)            {              if(visit[j]==1)               {                   printf("%d ",a[j]);               }            }        }    }    return 0;}

   但是还是有问题  样例能过 但是WA

下面测试一组数据  

5 9

1 2 3 4 10

输出结果竟然是 

2 3 4 10 

明显  10时多余的

为啥??????

if(!flag)        {            sum-=a[i];            visit[i]=0;        }

不知道注意到这没

我是在主函数外判断flag  再输出结果  

但是有一个问题  我递归的时候  最后递归结束的时候  会把我做的标记全部消除····

最后只知道YES  没法知道值

为了不让最后递归的时候 把我标记全清零  

那么我记  如果找到答案了  我就回溯的时候就不再清我的标记

但是  又出现个小尾巴 ,我递归10时把10标记了  

但是我找到答案了  又没有消除!!!那么成小尾巴了

 怎么办  那我只好找到答案直接赶紧趁热  输出 

要不递归问题多

void dfs(int pos){    if(flag==true)    {        printf("YES\n");        for(int j=0; j<n; j++)        {            if(visit[j]==1)            {                printf("%d ",a[j]);            }        }        return ;    }    if(sum>k)    {        return;    }    if(sum==k)    {        flag=true;        return;    }    for(int i=pos; i<n; i++)    {        sum+=a[i];        visit[i]=1;        dfs(i+1);        if(!flag)        {            sum-=a[i];            visit[i]=0;        }    }}

只把递归函数变了  

哈哈哈  没问题了~!!!

求豆麻袋   输出的结果由于我递归回去的时候  flag=true  一直成立  我就会输出很多组值~~~~~~

天天天天啊~~~~

再想  我让以第一次跟后面的都不一样

#include <cstdio>#include <cstring>using namespace std;int a[30],visit[30],n,k,sum;bool flag;void dfs(int pos){    if(sum==k)    {        flag=true;        printf("YES\n");        for(int j=0; j<n; j++)        {            if(visit[j]==1)            {                printf("%d ",a[j]);            }        }        printf("\n");        return ;    }    if(sum>k)    {        return;    }    for(int i=pos; i<n; i++)    {        sum+=a[i];        visit[i]=1;        printf("%d %d %d\n",pos,i,sum);        for(int k=0; k<n; k++)        {            printf("%d ",visit[k]);        }        printf("\n");        dfs(i+1);        if(!flag)        {            sum-=a[i];            visit[i]=0;        }    }}int main(){    int i;    while(scanf("%d%d",&n,&k)!=EOF)    {        for(i=0; i<n; i++)            scanf("%d",&a[i]);        memset(visit,0,sizeof(visit));        flag=false;        dfs(0);        if(!flag)            printf("NO\n");    }    return 0;}

提交  WA  !!!

还有个问题  第二次输入的值不正确

#include <cstdio>#include <cstring>using namespace std;int a[30],visit[30],n,k,sum;bool flag;void dfs(int pos){    if(sum==k)    {        flag=true;        printf("YES\n");        for(int j=0; j<n; j++)        {            if(visit[j]==1)            {                printf("%d ",a[j]);            }        }        printf("\n");        return ;    }    if(sum>k)    {        return;    }    for(int i=pos; i<n; i++)    {        sum+=a[i];        visit[i]=1;        /*printf("%d %d %d\n",pos,i,sum);        for(int k=0; k<n; k++)        {            printf("%d ",visit[k]);        }        printf("\n");*/        dfs(i+1);        sum-=a[i];        visit[i]=0;    }}int main(){    int i;    while(scanf("%d%d",&n,&k)!=EOF)    {        sum=0;        for(i=0; i<n; i++)            scanf("%d",&a[i]);        memset(visit,0,sizeof(visit));        flag=false;        dfs(0);        if(!flag)            printf("NO\n");    }    return 0;}

AC代码   发现不同没

没错

if(!flag)        {            sum-=a[i];            visit[i]=0;        }
这里改动一下~~~本来是为了防止回去时候把标记清除了的  

但是我已经提前输出结果了  标记无所谓了    没去掉

重点  他影响了第二次的运行  这个  为什么影响  大家下去自己思考

真的第一次写这么长的博客 记录我写一道题的经理

真的卡在这道题上太多时间~~~~

不过收获很大  时间用的还是很值得的 


总结;

做题不要看网上代码 

以前不会直接百度代码  不知道每一个代码都有这么多自己想不到的门道

先自己 写一个代码  (自己认为正确的)

即使出不来结果也无所谓了  我们慢慢改  

做一道会一道  


0 0
原创粉丝点击