
看來我還是太垃圾了,比賽的時候沒看出來這是一道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;
}
