《编程之美》——2.18数组分割
题目的意思大概是这样的: 一个数组的长度为2N,要求将数组分割成长度相同的两个序列,要求两个序列的和尽可能的接近!!或者说从中选出N个使他们的和最接近原来和的一半。
书中piapia~~~~!讲了很多~~~!!可是我没看懂!!!
我只能用最暴力的方法做了!
暴力的方法:2N个数中选取N个的所有情况,是不是就是N个0,和N个1的全排列;
比如N=2;我们假设1,0分别表示这个位置上的数被选入不同数组
那么所有情况为
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
好吧情况有点多!!!既然穷举法了,干脆一不做二不休,全排列也不自己写了!!!
用库函数next_premutation求全排列,先把选择设定为非减(字典序最小),不停调用这个函数,直到选择非增(字典序最大)!!记录每一种情况
#include<string>
#include<algorithm>
#include<iostream>
using namespace std;
int arr[]={1,5,7,8,9,6,3,11,20,17};
const int N=sizeof(arr)/sizeof(int);
int CurSelect[N];//当前的选择,0表示不选这个数,1表示选取这个数
int FinalSelect[N];//最后的选择结果
int sum()
{
int sum=0;
//计算当前数组的和
for(int i=0;i<N;i++)
if(CurSelect[i])
sum+=arr[i];
return sum;
}
int main(int argc,char* argv[])
{
//计算数组和的一半
int halfSum=0;
for(int i=0;i<N;i++)
halfSum+=arr[i];
halfSum/=2;
//初始化选择为最小的字典序(非减序列)
for(int i=0;i<N;i++)
CurSelect[i]=FinalSelect[i]=0;
for(int i=N-1;i>=N/2;i--)
CurSelect[i]=FinalSelect[i]=1;
int AnsSum=sum();
AnsSum=AnsSum>halfSum?AnsSum-halfSum:halfSum-AnsSum;
int tmp;
while(next_permutation(CurSelect,CurSelect+N)&&AnsSum!=0)//全排列
{
tmp=sum();
tmp=tmp>halfSum?tmp-halfSum:halfSum-tmp;
if(tmp<AnsSum)
{
for(int i=0;i<N;i++)
FinalSelect[i]=CurSelect[i];
AnsSum=tmp;
}
}
AnsSum=0;
int allsum=0;
for(int i=0;i<N;i++)
{
allsum+=arr[i];
if(FinalSelect[i])
{
AnsSum+=arr[i];
cout<<arr[i]<<" ";
}
}
cout<<endl;
cout<<"All Sum : "<<allsum<<endl;
cout<<"S1 Sum : "<<AnsSum<<endl;
system("pause");
return 0;
}