选与不选之DFS

有这么一类问题:枚举从N个整数中选择K个来知足某种条件。咱们能够在使用深度优先时,对每个元素均可以有选与不选两种方案(有的问题还能够屡次选)。
学到这招后,我会解了许多题,下面两个题我一开始就是用这种方法解得。但惋惜都不是最优解。
这种方法由于每一个元素都有两个选择,时间复杂度很高,下面举例进行说明。ios

例1: 一 得到特定数量硬币问题c++

小易准备去魔法王国采购魔法神器,购买魔法神器须要使用魔法币,可是小易如今一枚魔法币都没有,可是小易有两台魔法机器能够经过投入x(x能够为0)个魔法币产生更多的魔法币。算法

魔法机器1:若是投入x个魔法币,魔法机器会将其变为2x+1个魔法币测试

魔法机器2:若是投入x个魔法币,魔法机器会将其变为2x+2个魔法币spa

小易采购魔法神器总共须要n个魔法币,因此小易只能经过两台魔法机器产生刚好n个魔法币,小易须要你帮他设计一个投入方案使他最后刚好拥有n个魔法币。设计

输入描述: 输入包括一行,包括一个正整数n(1 ≤ n ≤ 10^9),表示小易须要的魔法币数量。code

输出描述: 输出一个字符串,每一个字符表示该次小易选取投入的魔法机器。其中只包含字符'1'和'2'。递归

输入例子1: 10ip

输出例子1: 122ci

由于每次都有两种选择,投1号箱或2号箱,个人思路以下:

#include<cstdio>
#include<vector>
using namespace std;

vector<int> ans,temp;
int n;
void getMagicCoin(int sum){
    
    if(sum>n) return;
    else if(sum==n){
        ans=temp;
    }
    
    temp.push_back(1);
    getMagicCoin(2*sum+1);
    temp.pop_back();
    
    temp.push_back(2);
    getMagicCoin(2*sum+2);
    temp.pop_back();
    
}
int main(){
    int sum=0;
    
    scanf("%d",&n);
    getMagicCoin(sum);
    
    for(int i=0;i<ans.size();i++){
        printf("%d",ans[i]);
    }
    return 0;
}

没问题,可是这种算法很暴力,极可能超时。
分析一下,能够获得以下的方案,就没有反复地递归,很好。

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

int main(){
    int n;
    cin>>n;
    string ans;
    while(n>=1){
        if(n%2==0){
            n=(n-2)/2;
            ans+='2';
        }else{
            n=(n-1)/2;
            ans+='1';
        }
    }

    reverse(ans.begin(),ans.end());
    cout<<ans<<endl;
    
    return 0;
}

例2:PAT甲级 1045 Favorite Color Stripe (30 分)

我又是用选与不选和DFS作的,虽然还作了剪枝,但仍是有两个测试点超时,以下:

//此方法有两个测试点超时 
#include<iostream>
#include<vector>
using namespace std;

const int maxn=10010;
const int maxm=210; 

int tripe[maxn];
int order[maxm];
bool like[maxm];
vector<int> temp,ans;
int cnt,maxL=0;

//idx:将要收集的颜色
//lastLikeLevel:上一个收集的颜色的喜欢程度 
void DFS(int idx,int lastLikeLevel){
    if(idx==cnt){
        if(temp.size()>maxL){
            maxL=temp.size();
            ans=temp;
        }
        return;
    }
    if(temp.size()+cnt-idx<maxL){//剪枝 
        return;
    }
    if(order[tripe[idx]]>=lastLikeLevel){
        temp.push_back(tripe[idx]);
        DFS(idx+1,order[tripe[idx]]);
        temp.pop_back();
        
        DFS(idx+1,lastLikeLevel);
//      temp.pop_back();
    }else{
        DFS(idx+1,lastLikeLevel);
    }
    
}
int main(){
    int n,m,l;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int a;
        cin>>a;
        order[a]=i;
        like[a]=true;
    }
    cin>>l;
    for(int i=0;i<l;i++){
        int a;
        cin>>a;
        if(like[a]){
            tripe[cnt++]=a;
        }
    }
    
    DFS(0,-1);
    cout<<maxL<<endl;
    
//  for(int i=0;i<ans.size();i++){
//      cout<<ans[i]<<" ";
//  }
    return 0;
}

其实这道题能够用动态规划来作,是要求【最长不降低子序列】,以下:

#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=10010;
const int maxm=210; 

int ht[maxm];
int tripe[maxn],dp[maxn];//dp[i]表示以i结尾的字符的最大子串长度

int main(){
    int n,m,l,x;
    cin>>n>>m;
    fill(ht,ht+maxm,-1);//刚开始写的是ht+m,一个测试点错误,很久没看到,必定要细心 
    for(int i=0;i<m;i++){
        cin>>x;
        ht[x]=i;
    }
    cin>>l;
    int cnt=0;
    for(int i=0;i<l;i++){
        cin>>x;
        if(ht[x]>=0){
            tripe[cnt++]=ht[x];
        }
    }
    int ans=-1;
    for(int i=0;i<cnt;i++){
        dp[i]=1;
        for(int j=0;j<i;j++){
            if(tripe[j]<=tripe[i]&&dp[i]<dp[j]+1){
                dp[i]=dp[j]+1;
            }
        }
        ans=max(dp[i],ans);
    }
    cout<<ans<<endl;

    return 0;
}

例三:PTA天梯赛 L3-001 凑零钱 (30 分)

//最后一个测试点超时
//求助 
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;

const int maxn=10010;
int a[maxn];
vector<int> ans,temp;
int n,m;
bool flg=false;

void func(int idx,int sum){
    
    if(sum>m||idx>n||flg==true){
        return; 
    }else if(sum==m){
        ans=temp;
        flg=true; 
        return;
    }
    temp.push_back(a[idx]);
    
    func(idx+1,sum+a[idx]);
    
    temp.pop_back();
    
    func(idx+1,sum);
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }   
    sort(a,a+n);
    func(0,0);
    if(flg){
        for(int i=0;i<ans.size();i++){
            cout<<ans[i];
            if(i<ans.size()-1) cout<<" ";
            else cout<<"\n";
        }
    }else{
        cout<<"No Solution\n";
    }
    
    return 0;
}
相关文章
相关标签/搜索