第十二届蓝桥杯 试题G:砝码称重
![](https://img2020.cnblogs.com/blog/2277174/202104/2277174-20210430152255247-299183339.png)
![](https://img2020.cnblogs.com/blog/2277174/202112/2277174-20211221201121680-1877973007.png)
看来我还是太垃圾了,比赛的时候没看出来这是一道dp题,用暴力的方法枚举了四个砝码能称出的重量,应该能过一部分样例
知道自己得了省一之后要开始准备国赛了,就想着把这道题重新写一下
动态规划思路如下:
从一个砝码开始,每个状态列举出当前可以被称出的重量
每次加入一个砝码,这时只需要将上一个状态的每个可以被称出的重量与新的砝码进行组合,即得出当前砝码数量可以被称出的所有重量
一直到最后一个砝码加入,最后一个状态就得出了所有可以被称出的重量
样例输入:3 1 4 6
第一个状态只有一个砝码,所以只有一个重量可以被称出来,就是1;
第二个状态加入了4,4,1+4=5,4-1=3,就是1,3,4,5;
第三个状态加入了6,6,1+6=7,6-1=5,3+6=9,6-3=3,4+6=10,6-4=2,5+6=11,6-5=1,就是1,2,3,4,5,6,7,9,10,11;
#include<bits/stdc++.h>
using namespace std;
int dp[105][100006]={0}; //动态规划数组
int a[105]; //砝码数组
int main()
{
int n,sum=0;
int ans=0;
cin>>n; //砝码数量
for(int i=0;i<n;i++)
{
cin>>a[i]; //输入每个砝码重量
sum+=a[i]; //确定每次遍历循环的最大值
}
dp[0][a[0]]=1; //第一个砝码的重量一定可以被称出来
int x;
for(int i=1;i<n;i++) //从第二个砝码开始动态规划
{
x=a[i]; //当前加入砝码的重量
for(int j=1;j<=sum;j++)
{
dp[i][j]=dp[i-1][j]; //复制前一组状态
}
dp[i][x]=1; //当前砝码一定可以被称出来
for(int j=1;j<=sum;j++)
{
if(dp[i-1][j]) //在上一状态的基础上加入一个新的砝码
{ //只需考虑上一状态的每个可以被称出的重量与当前砝码的组合
dp[i][j+x]=1;
dp[i][abs(j-x)]=1; //将新的组合置为1,表示可以被称出来
}
}
}
for(int i=1;i<=sum;i++) //将最后的状态遍历计数,即为可称出的重量的数量
if(dp[n-1][i]) ans++;
cout<<ans;
return 0;
}