洛谷P1441 砝碼稱重(加強版)
阿新 • • 發佈:2018-11-10
題目連結
解題思路:
搜尋/列舉+dp
dp過程參考弱化版的P2347 砝碼稱重。
妙啊,真的是妙啊…
感覺這題搜尋和dp結合的恰到好處。利用dfs先枚舉出所有可能的情況,當陣列
中被標記的數值達到
後,表示已經捨棄了
個值,在剩下的
個值裡面dp就行了。
在dp過程,由於題目資料範圍可知,所有砝碼的和一定不超過2000,所以用一個數組
表示
個砝碼組合得到的和可以是
,然後統計
裡面不為0的個數就可以了。
最後注意在更新
的過程中,逆序更新,防止之前更新的值影響已經更新過的值。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>//memset
using namespace std;
int n,m;
int a[30];
int vis[30],now=1;
int f[2010];//f[0]=1;
int ans=0;
void dp(){
memset(f,0,sizeof(f));
f[0]=1;
for(int i=1;i<=n;i++){
if(!vis[i]){
for(int j=2000;j>=a[i];j--){
if(f[j-a[i]]&&!f[j])
f[j]=1;
}
}
}
int cnt=0;
for(int i=1;i<=2000;i++){
if(f[i]) cnt++;
}
ans=max(ans,cnt);
}
void dfs(int k){
if(k==m) {
dp();
return;
}
for(int i=now;i<=n;i++){
if(!vis[i]){
vis[i]=1;
now=i+1;
dfs(k+1);//計數,列舉
vis[i]=0;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
dfs(0);
printf("%d\n",ans);
return 0;
}