问题描述
有n中不同大小的数字ai,每种mi个。判断是否可以从这些数字之中选出若干个使它们的和恰好为K
限制条件
1 <= n <= 100
1 <= ai, mi, <= 100000
1 <= K <= 100000
方式一
定义bool dp[i+1][j] 前i个数(含)能否加和为 j
for (int k = 0; k*a[i] <= j && k <= m[i]; k++)
dp[i+1][j] |= dp[i][j-k*a[i]];
这样程序的复杂度是O(K∑mi), 并且 bool dp 的信息有点浪费
方式二
定义dp[i+1][j] 前 i+1个数加和得到 j 时 第i个数能剩余多少个(没有时为-1)
dp[i+1][j] =
{
-1 (a[i] > j || dp[i+1][j-a[i]] <= 0) //大于j或者已经没有了
m[i] (dp[i][j] >= 0) //前i-1个数已经到达j 那么不需要消耗第i个数
dp[i+1][j-a[i]] - 1 (其他)
}
这样复杂度O(nK)
输入:
3
3 5 8
3 2 2
17
输出:
Yes
code:
#include <iostream>
using namespace std;
const int MAX=100000;
int n,k;
int a[MAX],m[MAX];
bool dp[100][MAX];
void solve()
{
int i,j,t;
for(i=1; i<k; i++)
dp[0][i]=false;
for(i=0; i<=n; i++)
dp[i][0]=true;
int r,f;
for(i=1; i<=n; i++)
{
for(j=1; j<=k; j++)
for(t=0; t<=m[i]&&t*a[i]<=j; t++)
dp[i][j]|=dp[i-1][j-t*a[i]];
for(r=1; r<=n; r++)
{
for(f=1; f<=k; f++)
cout<<dp[r][f]<<" ";
cout<<endl;
}
}
if(dp[n][k])
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
void solve1()
{
int i,j,t;
int d[MAX];
for(i=1; i<=k; i++)
d[i]=-1;
d[0]=0;
for(t=0; t<=k; t++)
cout<<d[t]<<" ";
cout<<endl;
for(i=1; i<=n; i++)
{
for(j=0; j<=k; j++)
{
if(d[j]>=0)
d[j]=m[i];
else if(j<a[i]||d[j-a[i]]<=0)
d[j]=-1;
else
d[j]=d[j-a[i]]-1;
}
for(t=0; t<=k; t++)
cout<<d[t]<<" ";
cout<<endl;
}
if(d[k]>=0)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
int main()
{
while(cin>>n)
{
int i;
for(i=1; i<=n; i++)
cin>>a[i];
for(i=1; i<=n; i++)
cin>>m[i];
cin>>k;
solve();
solve1();
}
return 0;
}