洛谷砝码称重

题目链接:https://www.luogu.com.cn/problem/P1441

其实这道题是一个很令人匪夷所思的题,它的做法是dp+dfs,这是令人意外的,也是我见识短的暴露;

我们采取的策略是在n个数字中删除m个数的方式,并且从第一个数一一枚举

通过dfs过程找到一种状态以后,求出使用当前留下的这些砝码可以凑出多少个不同的重量,我们通过dp解决这个问题。

观察题目可得,这个过程可以通过01背包实现。

定义dp[i][j]为当前选取到了第j个砝码,如果通过之前的砝码可以称量出重量i那么f[i][j]的值为true。

状态转移方程为: dp[i][j]=dp[i-a[i]][j-1]

初始状态为dp[0][j]=true

最后dp[i][n]中true的个数就是通过这些砝码可以计算出的重量值。

通过滚动数组,我们可以只定义一个f[i]数组,降低了时间复杂度,注意此时内层循环倒序。

注意事项以及参考代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[30];
 4 bool vis[30];
 5 bool dp[9000];
 6 int ans;
 7 int cnt;
 8 int tot;
 9 int n,m;
10 void DP()
11 {
12     memset(dp,0,sizeof(dp));
13     cnt=0;
14     tot=0;
15     dp[0]=true;
16     for(register int i=1;i<=n;i++)
17     {
18         if(vis[i])
19         continue;
20         for(register int j=tot;j>=0;j--)
21         {
22             if(dp[j]&&!dp[j+a[i]])
23             {
24                 dp[j+a[i]]=true;
25                 cnt++; 
26         }
27          }
28          tot+=a[i];//这个tot意为当前f[i]为真值的最大的i,极大加快了dp过程
29     }
30     ans=max(ans,cnt);
31  } 
32 void dfs(int xuanqu,int ji)
33 {
34     if(ji>m)
35     return ;
36     if(xuanqu>n)
37     {
38         if(ji==m)
39         {
40             DP();
41         
42         }
43         return ;//return 
44     }
45     dfs(xuanqu+1,ji);//选择当前的砝码 
46     vis[xuanqu]=true;//标记 
47     dfs(xuanqu+1,ji+1);//放弃当前的砝码 
48     vis[xuanqu]=false;//回溯一部 
49 }
50 int main()
51 {
52     ios::sync_with_stdio(false);
53     cin>>n>>m;
54     for(register int i=1;i<=n;i++)
55     cin>>a[i];
56     dfs(1,0);//开始枚举 
57     cout<<ans<<endl;
58     return 0;
59 }

 

posted @ 2022-03-20 11:45  江上舟摇  阅读(34)  评论(0编辑  收藏  举报