题意:有一个不多于100位的数字,满足各位之和为S1,各位平方之和为S2,求满足该条件的最小数字
思路:首先要理解,S1<=900,为什么呢?假设每一位的数字都取9,那么100位之和就为900,不能再多了,同理,S2<=8100。然后就可以将这个问题泛化为一个二维完全背包问题,有1-9种物品可以任意选,最后的价值是它们的和,体积是它们的平方和,那么DP[i][j]可以表示为要取i价值,j体积最少要取多少件物品。DP方程见代码
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 100000
#define LL long long
int cas=1,T;
#define INF 1000000
int dp[901][8110];
int a[10];
int num[910];
int pos;
void Print(int s1,int s2)
{
if (!s1 && !s2)
return;
for (int i = 1;i<=9;i++)
{
if (dp[s1-i][s2-a[i]] == dp[s1][s2]-1)
{
num[pos++] =i;
Print(s1-i,s2-a[i]);
return;
}
}
}
int main()
{
for (int i = 1;i<=9;i++)
a[i]=i*i;
for (int i = 0;i<=900;i++)
for (int j = 0;j<=8100;j++)
dp[i][j]=1000000;
dp[0][0]=0;
for (int i = 1;i<=9;i++)
for (int j = i;j<=900;j++)
for (int k = a[i];k<=8100;k++)
dp[j][k] = min(dp[j][k],dp[j-i][k-a[i]]+1);
//freopen("in","r",stdin);
scanf("%d",&T);
while (T--)
{
int s1,s2;
scanf("%d%d",&s1,&s2);
if (s1 > s2 || s1>900 || s2 > 8100)
printf("No solution\n");
else
{
if (dp[s1][s2]>100)
printf("No solution\n");
else
{
pos = 0;
Print(s1,s2);
for (int i = 0;i<pos;i++)
printf("%d",num[i]);
printf("\n");
}
}
}
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}