题解:本题主要考察dp+dfs。
简要题意:现有
n
n
n个砝码,重量分别为
a
1
,
a
2
,
a
3
,
…
…
,
a
n
,
a_1,a_2,a_3,……,a_n,
a1,a2,a3,……,an,在去掉
m
m
m个砝码后,问最多能称量出多少不同的重量(不包括0)。
1.dfs:dfs枚举不取哪
m
m
m个砝码的情况,然后对这些情况进行dp,用ans存储。
2.dp:设
f
[
i
]
[
j
]
f[i][j]
f[i][j]为当前选取到了第
i
i
i个砝码,总重量为
j
j
j。所以方程为:
f
[
i
]
[
j
]
=
f
[
i
−
a
[
i
]
]
[
j
−
1
]
f[i][j]=f[i-a[i]][j-1]
f[i][j]=f[i−a[i]][j−1](条件为
f
[
i
]
[
j
]
f[i][j]
f[i][j]没有选过和
f
[
i
]
[
j
−
a
[
i
]
]
f[i][j-a[i]]
f[i][j−a[i]]已经选过)
但是二维dp时间空间复杂度很高,可能超时,所以要降维。观察题目可得,这个过程其实是01背包的变形。所以得:
f
[
j
+
a
[
i
]
]
=
1
f[j+a[i]]=1
f[j+a[i]]=1
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int f[66666],a[66666],v[66666];
int n,m,ans,sum,tot;
void dfs(int p,int num)
{
if(num>m)return ;
if(p==n+1)
{
if(num==m)
{
sum=0;tot=0;
memset(f,0,sizeof(f));f[0]=1;
for(int i=1;i<=n;i++)
{
if(!v[i])
{
for(int j=2001;j>=0;j--)
if(f[j]&&!f[j+a[i]]){f[j+a[i]]=1;sum++;}
tot+=a[i];
}
}
ans=max(ans,sum);
}
return;
}
dfs(p+1,num);
v[p]=1;
dfs(p+1,num+1);
v[p]=0;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
dfs(1,0);
cout<<ans<<endl;
return 0;
}