题目
小C为了试验小X,便为物竞的小X出了一道物理相关的题:现在给出n个质量的砝码,问小X能称出多少种质量的物品,可是总有好事者想要破坏,于是乎,n达到了500,远远超出了小X能够承受的范围,锲而不舍的他决定寻求你们的帮助。
30%:n <=10
60%: n<=100
100%: n<=500 数据保证砝码的质量之和不超过20000
3 13
1
3
9
注意:天平有两边,两边均可放。
题解
判定DP,弄一弄就好了。也可以把每个数弄成负数和他自己,然后就是01背包
我居然一次就过了,很惊讶
首先要理解题意,你理解就好,给数据自行理解:
样例输入
3
9
4
20
样例输出
13
可以达到的重量 4 5 7 9 11 13 15 16 20 24 25 29 33
达到方式 4 9-4 20-4-9 9 20-9 4+9 20-9+4 20-4 20 20+4 20+9-4 20+9 20+4+9
f[j]=f[j+a[i]] or f[j-a[i]]
用我这个方法要注意:
为了没有后效性,减和加要分开做
时间复杂度O(20000n)
代码
var
n,nc,i,j,k,ans:longint;
f,c:array[0..100200]of boolean;
a:array[0..500]of longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure qsort(l,r:longint);
var
i,j,k,t:longint;
begin
if l>=r then exit;
i:=l;j:=r;
k:=a[(l+r) div 2];
repeat
while a[i]>k do inc(i);
while a[j]<k do dec(j);
if i<=j then
begin
t:=a[i];a[i]:=a[j];a[j]:=t;
inc(i);dec(j);
end;
until i>j;
qsort(i,r);
qsort(l,j);
end;
begin
readln(n);
for i:=1 to n do
begin
readln(a[i]);
nc:=nc+a[i];
end;
f[0]:=true;
qsort(1,n);
for i:=1 to n do
begin
c:=f;
for j:=1 to nc do
if f[j+a[i]] then
f[j]:=true;
for j:=nc downto 1 do
if c[j-a[i]] and (j-a[i]>=0) then
c[j]:=true;
for j:=1 to nc do
if c[j] then f[j]:=true;
end;
for i:=1 to nc do
if f[i]=true then inc(ans);
writeln(ans);
end.