洛谷P1441 砝码称重(加强版)

题目链接

P1441 砝码称重

解题思路:

搜索/枚举+dp
dp过程参考弱化版的P2347 砝码称重
妙啊,真的是妙啊…
感觉这题搜索和dp结合的恰到好处。利用dfs先枚举出所有可能的情况,当数组 a [ i ] a[i] 中被标记的数值达到 m m 后,表示已经舍弃了 m m 个值,在剩下的 n m n-m 个值里面dp就行了。
在dp过程,由于题目数据范围可知,所有砝码的和一定不超过2000,所以用一个数组 f [ i ] f[i] 表示 n m n-m 个砝码组合得到的和可以是 i i ,然后统计 f [ i ] f[i] 里面不为0的个数就可以了。
最后注意在更新 f [ i ] f[i] 的过程中,逆序更新,防止之前更新的值影响已经更新过的值。

#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;
} 
参考思路:

https://www.luogu.org/blog/yeyangrui/solution-p1441

猜你喜欢

转载自blog.csdn.net/zhuixun_/article/details/82954036