• 给定非负数组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的次方来避免)。

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

  • 相关阅读:
    BZOJ 3811: 玛里苟斯 线性基
    HDU 3949 XOR 线性基
    BZOJ 2115: [Wc2011] Xor 线性基 dfs
    BZOJ 3963 HDU3842 [WF2011]MachineWorks cdq分治 斜率优化 dp
    BZOJ 3262: 陌上花开 cdq分治 树状数组
    BZOJ 2653: middle 主席树 二分
    BZOJ 3524 [Poi2014]Couriers 主席树
    BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树
    BZOJ 3956: Count 主席树 可持久化线段树 单调栈
    2018/4/9省选模拟赛 0分
  • 原文地址:https://www.cnblogs.com/lvfq/p/3020732.html
Copyright © 2020-2023  润新知