给定非负数组A与数字M,求数组A中和最接近M的元素

DestinationSum.h

#ifndef DESTINATIONSUM_H
#define DESTINATIONSUM_H

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

class DestinationSum
{
public:
    DestinationSum();
    ~DestinationSum();

    void execute(vector<int>& data,int sum,vector<int>& result);
    void execute(vector<int>& data,int sum,string& result);
    void execute(vector<double>& data,double sum,vector<double>& result);
    void execute(vector<double>& data,double sum,string& result);

private:
    void backtrace(double current_sum,int level);
    void backtrace(vector<vector<int> >& bestV);

    vector<bool> m_solution;
    vector<bool> m_result;

    vector<double> m_datad;
    vector<double> m_datasumd;
    double m_sumd;
    double m_bestd;

    vector<int> m_datai;
    int m_sumi;
};

#endif

DestinationSum.cpp

#include "DestinationSum.h"
#include <algorithm>

DestinationSum::DestinationSum()
{
}

DestinationSum::~DestinationSum()
{
}

void DestinationSum::execute(vector<double>& data,double sum,vector<double>& result)
{
    //初始化
    m_result.clear();
    m_solution.resize(data.size(),false);

    result.clear();
    m_datad=data;
    m_sumd=sum;
    m_bestd=-1;

    //排序
    sort(m_datad.begin(),m_datad.end(),greater<int>());
    m_datasumd.resize(m_datad.size(),0);
    m_datasumd[m_datasumd.size()-1]=m_datad[m_datad.size()-1];
    for(int i=m_datad.size()-2;i>=0;i--)
    {
        m_datasumd[i]=m_datasumd[i+1]+m_datad[i];
    }

    backtrace(0,0);

    for(int i=0;i<m_result.size();i++)
    {
        if(m_result[i])
            result.push_back(m_datad[i]);
    }
}

void DestinationSum::execute(vector<double>& data,double sum,string& result)
{
    vector<double> vector_result;
    execute(data,sum,vector_result);

    result.clear();
    double total=0;
    char num[256];
    result="Solution: ";
    for(int i=0;i<vector_result.size();i++)
    {
        sprintf(num,"%f",vector_result[i]);
        total+=vector_result[i];
        result=result+string(num)+" ";
    }
    result+="\n";
    sprintf(num,"%f",total);
    result=result+"Sum: "+string(num);
    result+="\n";
}

void DestinationSum::backtrace(double current_sum,int level)
{
    if(current_sum>=m_sumd || level==m_datad.size())
    {
        if(m_bestd<0 || abs(current_sum-m_sumd)<=m_bestd)
        {
            m_bestd=abs(current_sum-m_sumd);
            m_result=m_solution;
        }
    }
    else if(current_sum+m_datasumd[level]<=m_sumd)
    {
        current_sum+=m_datasumd[level];
        if(m_bestd<0 || abs(current_sum-m_sumd)<=m_bestd)
        {
            m_bestd=abs(current_sum-m_sumd);
            for(int i=level;i<m_solution.size();i++)
            {
                m_solution[i]=true;
            }

            m_result=m_solution;

            for(int i=level;i<m_solution.size();i++)
            {
                m_solution[i]=false;
            }
        }
    }
    else if(current_sum<m_sumd && current_sum+m_datasumd[level]>m_sumd )
    {
        backtrace(current_sum,level+1);

        m_solution[level]=true;
        backtrace(current_sum+m_datad[level],level+1);
        m_solution[level]=false;
    }
}

void DestinationSum::execute(vector<int>& data,int sum,vector<int>& result)
{
    m_solution.resize(data.size(),false);

    result.clear();
    m_sumi=sum;
    m_datai=data;

    vector<vector<int> > bestV;
    int count=data.size();
    bestV.resize(count);
    for(int i=0;i<count;i++)
    {
        bestV[i].resize(sum+1);
    }
    for(int i=0;i<=sum;i++)
    {
        bestV[count-1][i]=min(i,abs(data[count-1]-i));
    }

    for(int i=count-2;i>0;i--)
    {
        int boundary=min(data[i],sum);
        for(int j=0;j<boundary;j++)
        {
            bestV[i][j]=bestV[i+1][j];
        }
        for(int j=boundary;j<=sum;j++)
        {
            if(data[i]<sum)
                bestV[i][j]=min(bestV[i+1][j],bestV[i+1][j-boundary]);
            else
                bestV[i][j]=bestV[i+1][j];
        }
    }
    if(count>1)
    {
        if(data[0]<=sum)
        {
            bestV[0][sum]=min(bestV[1][sum],bestV[1][sum-data[0]]);
        }
        else
        {
            bestV[0][sum]=bestV[1][sum];
        }
    }

    backtrace(bestV);

    for(int i=0;i<data.size();i++)
    {
        if(m_solution[i])
            result.push_back(data[i]);
    }
}

void DestinationSum::execute(vector<int>& data,int sum,string& result)
{
    vector<int> vector_result;
    execute(data,sum,vector_result);

    result.clear();
    int total=0;
    char num[256];
    result="Solution: ";
    for(int i=0;i<vector_result.size();i++)
    {
        sprintf(num,"%d",vector_result[i]);
        total+=vector_result[i];
        result=result+string(num)+" ";
    }
    result+="\n";
    sprintf(num,"%d",total);
    result=result+"Sum: "+string(num);
    result+="\n";
}

void DestinationSum::backtrace(vector<vector<int> >& bestV)
{
    int sum=m_sumi;
    for(int i=0;i<bestV.size()-1;i++)
    {
        if(bestV[i][sum]==bestV[i+1][sum])
            m_solution[i]=false;
        else
        {
            m_solution[i]=true;
            sum-=m_datai[i];
        }
    }
    if(bestV[bestV.size()-1][sum]==sum)
        m_solution[bestV.size()-1]=false;
    else
        m_solution[bestV.size()-1]=true;
}

main.cpp

#include <DestinationSum.h>

int main(int argc,char *argv[])
{
    //vector<double> data;
    //vector<double> result;
    //double a[]={264,13340,18340,5000,14020,29060,9780,22194,21820,2460,20520,2460,2460,2460,11560,22630,4920,7000,26880,18260,25216,28620,28520,4240,10000,16220,4240,12000,3200,12916,2250,9834,2460,4860,984,11360,26760,6396,9840,3444,4860};
    //for(int i=0;i<sizeof(a)/sizeof(double);i++)
    //{
    //    data.push_back(a[i]);
    //}
    //DestinationSum ds;
    //ds.execute(data,158500,result);
    //int total=0;
    //for(int i=0;i<result.size();i++)
    //{
    //    total+=result[i];
    //    cout<<result[i]<<" ";
    //}
    //cout<<" total: "<<total<<endl;

    vector<int> data,result;
    int a[]={264,13340,18340,5000,14020,29060,9780,22194,21820,2460,20520,2460,2460,2460,11560,22630,4920,7000,26880,18260,25216,28620,28520,4240,10000,16220,4240,12000,3200,12916,2250,9834,2460,4860,984,11360,26760,6396,9840,3444,4860};
    for(int i=0;i<sizeof(a)/sizeof(int);i++)
    {
        data.push_back(a[i]);
    }
    DestinationSum ds;
    ds.execute(data,158500,result);
    int total=0;
    for(int i=0;i<result.size();i++)
    {
        cout<<result[i]<<" ";
        total+=result[i];
    }
    cout<<endl<<total<<endl;
    system("pause");
    return 0;
}

 

这就是全部的代码了。

用到了两种方法:

回溯和动态规划(类似01背包)。

回溯的方法太慢了,因为是O(2^n),虽然尽量剪枝了,还是很慢;

动态规划的方法就比较快,但是对数据类型有限制(其实小数可以用乘以10的次方来避免)。

 

下一个版本代码实现存储多个最优解。(当前只能输出最优值,并且得到其中一个解,下一版本尝试得到多个解)

posted @ 2013-04-14 19:03  风中精灵LvFQ  阅读(223)  评论(0编辑  收藏  举报