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的次方来避免)。
下一个版本代码实现存储多个最优解。(当前只能输出最优值,并且得到其中一个解,下一版本尝试得到多个解)