题意:有n个砝码,你不知道每个砝码的重量,但是你的朋友知道,你可以每次拿出k个砝码给你的朋友,他会告诉你k个砝码的重量和,经过1次尝试之后,你最多可以区分出多少个砝码?
题解:首先对于你拿出的k个砝码,若要想区分出来,这k个砝码必然是相同的且其质量和的方案数唯一,那么对于所有砝码的重量和的方案数可以用多重背包来求解,最后特判只有2种物品的就可以了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
using namespace std;
int n;
int dp[2][105][10005];
int vis[105];
int a[105];
int main() {
while(~scanf("%d",&n))
{
int sp=0;
map<int,int>mp;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(mp[a[i]]==0)
sp++;
mp[a[i]]++;
}
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
int cur=0;
dp[cur][0][0]=1;
for(int i=1;i<=n;i++)
{
if(vis[a[i]]==0)
{
cur^=1;
int cnt=mp[a[i]];
for(int j=0;j<=10000;j++)
for(int k=0;k<=100;k++)
dp[cur][k][j]=dp[cur^1][k][j];
for(int j=1;j<=cnt;j++)
{
for(int k=10000;k>=j*a[i];k--)
{
for(int l=100;l>=j;l--) {
dp[cur][l][k] += dp[cur ^ 1][l-j][k - j * a[i]];
dp[cur][l][k] = min(2, dp[cur][l][k]);
}
}
}
vis[a[i]]=1;
}
}
memset(vis,0,sizeof(vis));
int ans=0;
int id=0;
for(int i=1;i<=n;i++)
{
if(vis[a[i]]==0)
{
int cnt=mp[a[i]];
for(int j=cnt;j>=1;j--)
{
if(dp[cur][j][j*a[i]]==1) {
if (ans < j) {
ans = j;
id = i;
}
}
}
vis[a[i]]=1;
}
}
if(sp==2 && mp[a[id]]==ans)
ans=n;
printf("%d\n",ans);
}
return 0;
}