目标函数转化求解Set partitioning问题

来源:互联网 发布:淘宝好还是京东商城好 编辑:程序博客网 时间:2024/06/15 19:34
描述

There are some positive integer numbers, and you want to divide them into two nonempty sets (every integer should be in and only in one set) and get a value descripted below:

Assume that set A has n1 numbers A1, A2, ...,An1; set B has n2 numbers B1, B2, ...Bn2.

Let

Then

 

We want to know the largest ans.

输入

The first line of the input is an integer T (T <= 20), which stands for the number of test cases you need to solve.

Every test case begins with an integer N (2 <= N <= 10000), then followed by N positive integers on the next line, these numbers will not exceed 1000.

输出

For every test case, you should output "Case #k: " first, where k indicates the case number and starts at 1. Then output the answer rounded to two digits after the decimal point. See sample for more details.

样例输入

2
3
1 1 1
3
1 2 3

样例输出

Case #1: 0.00
Case #2: 7.25

 

思路:

   将输入数据从小到大排列后, 问题为求一个位置i (0<=i<n), 使得以i为界的两个部分(第i个位置的元素属于第一部分)满足目标函数:

                                             max

 如果线性搜索i ,计算每个ans求得最大值, 遍历时间为O(n),计算时间为O(n),总的时间复杂度为O(n2), 在10000的数据规模下会超时。

 

此处,需要将目标函数进行拆分转义,得到化简后的目标函数为:

                                         所有元素的平方和(定值)+ n1*v2*v2+n2*v1*v1-2*v1*v2*n ;

 其中 ,n1= i+1,n2=n-i-1  . v1,v2也容易求得。

这样计算的时间复杂度降为O(1),总的时间复杂度为O(n)。

 

代码:

#include<iostream>#include<algorithm>using namespace std;int main(){int t,k,i,j,sum,n;int s[10001],num[10001];double max=-999999,temp,result;double a,b,aa,bb;double e=0.000001;int mark=0;cin>>t;for(k=1;k<=t;k++){cin>>n;sum=0;temp=0;max=0;result=0;for(i=0;i<n;i++){cin>>num[i];temp+=num[i]*num[i];}sort(num,num+n);for(i=0;i<n;i++){sum+=num[i];s[i]=sum;}for(i=0;i<n-1;i++){a=1.0*s[i]/(i+1);b=1.0*(sum-s[i])/(n-i-1);//cout<<"*"<<a<<" "<<b<<endl;result=temp+1.0*((i+1)*b*b+(n-i-1)*a*a-2*a*b*n);if(result>max){//cout<<i<<" "<<temp<<endl;max=result;mark=i;aa=a;bb=b;//cout<<aa<<bb<<endl;}}        printf("Case #%d: %.2lf\n",k,max);}}


 

 

 

 

 

0 0