115.子集和的目标值(大数据的01背包)

1692 子集和的目标值

 

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
题目描述 Description

给定n个整数in和目标值T,求某一非空子集使 子集的元素的和 与 目标值之差 的绝对值最小,元素可重复

输入描述 Input Description

第一行为整数n T

n为整数个数,T为目标值

第二行为n个整数in

输出描述 Output Description

一个整数d,为差的最小值的绝对值

样例输入 Sample Input

5 9

1 1 1 4 17

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

1<=n<=101

0<=T<=2147483647

0<=in<=2147484647

放心,n很大的时候数据都很弱……

分类标签 Tags 点此展开 

注意题目中的“元素可重复”,并不是指完全背包,而是指输入的元素有可能有重复。
代码:
#include< iostream >
#include< cstdio >
#include< cstdlib >
#include< cmath >
#include< algorithm >
using namespace std;
long long int f[3000010];
long long int  a[101];
int n;
long long int t;int sum=9999999;
void dfs(int i,int j)//j da shu
{
if(i>=j)
return;
if(abs(a[j]-t)
    {
    if(abs(a[j]-t)
    {
    sum=abs(a[j]-t);
    dfs(i,j-1);
   
}
else{
sum=abs(a[i]+a[j]-t);
dfs(i+1,j-1);
}
    }
}
int main()
{
cin>>n>>t;
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
if(t>=pow(10,7))//对于超大数据进行特别判断,否则循环会死掉,次数太多了 
{
  
  
  if(n==1)
  {
  printf("%d",abs(t-a[1]));//特判n==1,防止sum未经过计算直接输出的情况 
  return 0;
  }
  sort(a+1,a+n+1); //深搜所有情况2个结合和一个结合的情况,因为t很大时,会有一个a[i]很大,不用担心 
  dfs(1,n);
  printf("%d",sum);
  return 0;
}
for(int i=1;i<=n;++i)//对于一般的数据就跑01背包就可以了 
 for(long long int j=t*2;j>=a[i];--j)
 f[j]=max(f[j],f[j-a[i]]+a[i]);
int p1=t-f[t];
int p2=0;
for(long long int i=t+1;i<=2*t;++i)
if(f[i]==i)
{
p2=f[i];
break;
}
if(p2==0)
p2=f[t+1];
p2=abs(p2-t);//这里要用abs函数,上面不用因为p1》=0一定对,但是p2在所有容积背包都装不满的情况下,会是负的。 
cout<<min(p1,p2);
return 0;
}
原文地址:https://www.cnblogs.com/c1299401227/p/5370702.html