選與不選之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;
}
相關文章
相關標籤/搜索