用一个二进制数表示能表示的所有重量的状态,那么就可以用一个数组来记录价值,每个价值所能表示的状态用上述的二进制数来表示,然后记录下路径就可以了,只要能想到用一个longlong的二进制数来表示所有重量的状态,这题就没什么难的了。
附代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <map>
#define LL unsigned long long int
using namespace std;
LL dp[200001];
LL mm=((1LL<<52)-1);
int use[55][200001];
LL v[410];
LL w[410];
int n,q;
map <LL,int> mp;
LL lowbit(LL x)
{
return x&(-x);
}
void init() //记录每个数是2的多少倍
{
LL a=2;
for (int i=1;i<=55;i++)
{
mp[a]=i;
a*=2;
}
return ;
}
void solve()
{
memset(dp,0,sizeof(dp));
memset(use,0,sizeof(use));
dp[0]=1;
for (int i=1;i<=n;i++)
{
scanf("%d%d",&w[i],&v[i]);
for (int k=200000-v[i];k>=0;k--)
{
if (dp[k]==0)
continue ;
int s=k+v[i];
LL p=dp[s];
dp[s]|=((dp[k]<<w[i])&(mm));
LL j=((p^dp[s])&dp[s]);
while (j>0)
{
LL x=lowbit(j);
j-=x;
if (x!=1)
use[mp[x]][s]=i;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
init();
while (T--)
{
scanf("%d%d",&n,&q);
solve();
int w1,t1;
for (int i=1;i<=q;i++)
{
scanf("%d%d",&w1,&t1);
if (!use[w1][t1])
{
printf("No solution!\n");
continue ;
}
printf("%d",use[w1][t1]);
int pp=use[w1][t1];
w1-=w[pp];
t1-=v[pp];
while (w1>0)
{
printf(" %d",use[w1][t1]);
pp=use[w1][t1];
w1-=w[pp];
t1-=v[pp];
}
printf("\n");
}
}
}