IAI上海月赛系列文章目录
文章目录
T1 天平砝码V2
思路一 暴力枚举法O(3^n)
#include<stdio.h>
int n;
int res;
int w[1000000];
bool st[100000];
void dfs(int k,int sum)//表示k个的砝码,重量是sum
{
if(k>n)//k>n 说明选完n个砝码
{
if(sum>0&&!st[sum])// 判断选出来的n个砝码的重量是否没被标记过 ,如没标记则答案加1
{
res++;
st[sum]=true;//标记这个重量
return;
}
}
//还没选够n个砝码
else
{
dfs(k+1,sum-w[k]);//砝码放右边
dfs(k+1,sum);//跳过,不适用当前的砝码
dfs(k+1,sum+w[k]);//砝码放左边
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
dfs(0,0);
printf("%d",res);
}
思路二 动态规划dp
进入第i个砝码时候可以,我们需要先更新dp(i, ai) = 1;
当dp(i-1,j)=1时,第i个砝码重量为ai,
状态转移如下:
-
dp (i , j) = 1,第i个砝码不使用
-
dp (i,j+ai)=1,第i个砝码和之前能称出的重量j相加
-
dp(i,j-ai)=1,两相减,注意可能小于0.需要加绝对值。
-
dp(i,ai-j)=1,两相减,注意可能小于0.需要加绝对值。
普通版本(内存未优化)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
bool dp[105][100005]; //dp[i][j]=1表示i个砝码可以称出重量j
int a[105];
int sum;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i]; //计算出可以称出的最大重量
}
dp[1][a[1]]=1;
for(int i=2;i<=n;i++) //枚举每个砝码 (加入每个砝码)
{
dp[i][a[i]]=1; //当前砝码的重量一定可以称出来
for(int j=1;j<=sum;j++) //复制状态,加入当前砝码前可以称得的重量加入后也可以得到
if(dp[i-1][j])//如果i-1个砝码可以称出j,那么枚举加入新的砝码可以称得的重量
{
dp[i][j]=dp[i-1][j];
dp[i][j+a[i]]=1;
dp[i][abs(j-a[i])]=1;
}
}
int ans=0;
for(int j=1;j<=sum;j++)
{
if(dp[n][j]!=0)
ans++;
}
cout<<ans<<endl;
return 0;
}
内存优化版本
实际上只要用到dp(i-1) 和dp(i) 两个状态。因此我们可以把空间做一次优化。
#include<iostream>
#include<algorithm>
using namespace std;
//bool dp[107][100005];//表示前i个砝码,可以表示的重量j
bool dp[100005],f[100005];//空间优化
int a[107];
int sum;
int main()
{
freopen("11.txt", "r", stdin) ;
int n;
scanf("%d", &n);
for (int i = 1;i<=n;i++)
{
cin >> a[i];
sum += a[i];
}
for (int i = 1;i<=n;i++)
{
//把dp中的值给f
for (int i = 0;i < sum;i++)
f[i] = dp[i];
for (int j = 1; j <= sum; j++)
{
if (f[j])
{
dp[abs(j - a[i])] = 1;
dp[j + a[i]] = 1;
}
}
dp[a[i]] = 1;
}
int res = 0;
for (int i = 1;i<100005;i++)
if(dp[i])res++;
cout << res << endl;
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
//bool dp[107][100005];//表示前i个砝码,可以表示的重量j
bool dp[2][100005];//空间优化
int main()
{
int n;
scanf("%d", &n);
for (int i = 1;i<=n;i++)
{
int ai;
scanf(