子集和問題—回溯


一、問題簡介

描述

子集和問題的一個實例為〈S,t〉。其中,S={ x1 , x2 ,…,xn }是一個正整數的集合,c是一個正整數。子集和問題判定是否存在S的一個子集S1,使得:SUM(S1) = c

試設計一個解子集和問題的回溯法。

對於給定的正整數的集合S={ x1 , x2 ,…,xn }和正整數c,計算S 的一個子集S1,使得:SUM(S1)=c。

Input

輸入數據的第1 行有2 個正整數n 和c(n≤10000,c≤10000000),n 表示S 的大小,c是子集和的目標值。接下來的1 行中,有n個正整數,表示集合S中的元素。

Output

將子集和問題的解輸出。當問題無解時,輸出“No Solution!”。

Sample Input

5 10
2 2 6 5 4

Sample Output

2 2 6

二、問題分析

排列樹回溯

時間復雜度為 O(n!) 可通過加限制條件達到剪枝效果

三、代碼

#include <iostream>
 
using namespace std;
 
int n=0,c=0;
int d[10050];
int t[10050];
int l=0;
int flag = 0;
int mysum = 0;
 
void backtrack(int,int,int);
 
int main(){
    //輸入
   cin>>n>>c;
    for (int i = 0; i < n; ++i) {
        cin>>d[i];
    }
 
    //回溯調用
    for (int i = 1; i <= n; ++i) {
        backtrack(i,0,n-1);
        if(flag == 1)
            break;
    }
 
    //輸出
    if (flag == 0){
        cout<<"No Solution!"<<endl;
    }
    else{
        for (int i = 0; i < l-1; ++i) {
            cout<<t[i]<<' ';
        }
        cout<<t[l-1]<<endl;
    }
}
void backtrack(int x,int s1,int s2){
 
    if (x == 0){
        if(mysum == c)
            flag = 1;
        //cout<<mysum<<endl;
        return;
    }
 
    for (int i = s1; i <= s2; ++i) {
        mysum += d[i];
        t[l++] = d[i];
        if (mysum<=c)   //剪掉不可能的分支
            backtrack(x-1,i+1,s2);
        if (flag == 1)  //找到結果,退出
            return;
        l--;
        mysum -= d[i];
    }
 
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM