How much weight can you lift?

Python 2, \$ O(2^{\frac{|W|}2} \cdot |B| \cdot |W| + |W|^2) \$, 203 bytes

Naive implementation, looks at all combinations of possible weights \$W\$ and barbells \$B\$.

lambda B,W,T:min([(w+w[::-1],b)for w in p(sorted(sum([W.count(x)/2*[x]for x in set(W)],[])))for b in B],key=lambda(a,b):((T-sum(a)-b)**2,len(a)))
p=lambda l:l and[l[:1]+x for x in p(l[1:])]+p(l[1:])or[l]

Try it online!

Ungolfed

def f(Barbells, Weights, Target):
  # For every pair of same weights keep one, order them ascending
  usable_weights = concat([Weights.count(x)/2 * [x] for x in set(Weights)])
  usable_weights = sorted(usable_weights)

  # list all possible combinations of symmetric weights and barbells
  possible_setups = [(w+w[::-1], b)for w in powerset(usable_weights)for b in Barbells]

  # Find the one with the weight being the closest to the target,
  # on a tie take the one with the lowest number of weights
  return min(possible_setups, key=lambda(a,b): ((Target - sum(a) - b)**2, len(a)))

concat = lambda ls:sum(ls, [])
powerset = lambda l:l and [l[:1]+x for x in powerset(l[1:])]+powerset(l[1:]) or [[]]

Try it online!


C++ (gcc), \$ O(2^{\frac{|P|}4} \times (|B| + \frac{|P|}2)) \$, 933 bytes

Input/Output Format

Takes as input a vector of plates \$ P \$, a vector of barbells \$ B \$, and a target weight \$ W \$. It outputs the plate arrangement on the first line, and the barbell on the second line.

#include <bits/stdc++.h>
using namespace std;using d=double;
int f(auto b,auto p,d w){
unordered_map<d,int>u;vector<d>s,A,B;
for(auto i:p)u[i]++;
for(auto i:u)while((i.second-=2)>=0)s.push_back(i.first*2);
int z=s.size(),i,j,k;vector<pair<d,vector<d>>>x(1<<z/2),y(1<<z/2+1);d m=DBL_MAX,n,r;
for(i=0,k=1;i<z/2;i++){
for(j=0;j<k;j++)x[j+k]=x[j];
for(;j<k*2;j++)x[j].first+=s[i],x[j].second.push_back(s[i]/2);
auto _=x.begin();inplace_merge(_,_+k,_+k*2);k*=2;
}
for(k=1;i<z;i++){
for(j=0;j<k;j++)y[j+k]=y[j];
for(;j<k*2;j++)y[j].first+=s[i],y[j].second.push_back(s[i]/2);
auto _=y.begin();inplace_merge(_,_+k,_+k*2);k*=2;
}
for(auto f:b)
for(i=0,j=(1<<z-z/2)-1;i<1<<z/2&&j>=0;n>w?j--:i++){
n=x[i].first+y[j].first+f;
if(abs(n-w)<m)r=f,A=x[i].second,B=y[j].second,m=abs(n-w);
}
A.insert(A.end(),B.begin(),B.end());
sort(A.begin(),A.end());for(auto i:A)cout<<i<<' ';
reverse(A.begin(), A.end());for(auto i:A)cout<<i<<' ';
cout<<'\n'<<r;
}

Try it online!

Explanation

The algorithm calculates all possible subset sums \$ S \$ of \$ P \$, and then finds the sum \$ s + b \$ which is closest to \$ W \$, where \$ s \$ and \$ b \$ are elements in \$ S \$ and \$ B \$, respectively. Using the meet-in-the-middle approach decreases the complexity quite a bit. (I'm aware this code is super long, and I'll try to shrink it a bit eventually).