NYOJ1282--DFS剪枝入门

链接戳这里

这道题呢 是一个入门深搜  看到题目很明显的dfs  

但是今天好好研究了下这道题  主要是想学习理解下剪枝的思想

题目

给你n个数(a1,a2,a3.......an) ,是否存在某一些数字加起来等于k,有就输出 "YES",否则输出 "NO"。

数据范围:n<20;          a1+a2+....an在int范围里面.

多组输入,每组第一行输入两个数n,k,第二行输入n个数a1 a2 ...... an

输出  如果存在一些数加起来为k输出"YES";否则输出"NO".

看范围  只有20个数  直接深搜也不会超时   但是我们通过这个题 可以理解下剪枝的思想

DFS的方法就不多说了  大家自己看代码   下面给出 两种未剪枝的DFS代码

时间消耗 492

//时间 492
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e5+7;
int v[maxn],a[maxn],flag,sum,n,k;
void dfs(int x){
    if(sum==k){
        flag=1;return;
    }
    for(int i=x;i<=n;i++){
        sum+=a[i];
        dfs(i+1);
        sum-=a[i];
    }
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        memset(a,0,sizeof(a));
        memset(v,0,sizeof(v));
        flag=0;sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        dfs(1);sum=0;
        if(flag==0)printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

  时间消耗340

// 时间 340
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100],sum,n,k;
bool dfs(int x,int sum){
    if(x==n) return sum==k;
    if(sum==k) return true;
    if(dfs(x+1,sum))return true;
    if(dfs(x+1,sum+a[x+1]))return true;
    return false;
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        memset(a,0,sizeof(a));
        sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        if(dfs(0,sum))printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

剪枝

这两种DFS  一个时间是492    一个是340

那么剪枝 就是深搜过程中 对于某些肯定不可能的情况就不要深入搜索了

比如这道题  找一部分数的和等于k  那么我们从小到大排序  从头开始找 

如果加上当前位置的数字后  sum大于k了 那么就不要往下找了 因为下面的数字  都比当前位置的大  肯定不行

所以 我们给这两种DFS 加个排序 再剪枝一下 

根据OJ的反馈   第一种方法优化后时间为32    第二种优化后时间为12   大大的减少了时间消耗

其他的DFS题目  我们要学会根据题意 找出不可能的状态  对我们的DFS剪枝优化

优化后

时间消耗 32  剪枝处在代码中有标示

//时间 32
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e5+7;
int v[maxn],a[maxn],flag,sum,n,k;
void dfs(int x){
    if(sum==k){
        flag=1;return;
    }
    if(sum>k)return ;//剪枝!
    for(int i=x;i<=n;i++){
        sum+=a[i];
        dfs(i+1);
        sum-=a[i];
    }
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        memset(a,0,sizeof(a));
        memset(v,0,sizeof(v));
        flag=0;sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1);
        dfs(1);sum=0;
        if(flag==0)printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

时间消耗 12  剪枝处在代码中有标示

// 时间 12
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100],sum,n,k;
bool dfs(int x,int sum){
    if(x==n) return sum==k;
    if(sum==k) return true;
    if(sum>k) return false;//剪枝!
    if(dfs(x+1,sum))return true;
    if(dfs(x+1,sum+a[x+1]))return true;
    return false;
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        memset(a,0,sizeof(a));
        sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1);
        if(dfs(0,sum))printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/holly_Z_P_F/article/details/82019969