问题:
给出一个正整数n,寻找最少的完全平方数,使他们的和为n
完全平方数:1,4,9,16 …
12 = 4+4+4
13 = 4+9
解法一:动态规划
状态转移方程:F(n) = min{ F(n-ai) + 1 } 其中ai为小于等于n的完全平方数
int a[100005];
int func(int n)
{
if (n <= 0)
return -1;
for (auto i = 1; i <= n;++i)
{
a[i] = 99999;
}
int min_tmp;
int tmp;
for (auto i = 1; i <= n;++i)
{
min_tmp = 99999;
for (auto j = 1; j*j <= i;++j)
{
tmp = a[i - j*j] + 1;
if (tmp<min_tmp)
{
min_tmp = tmp;
}
}
a[i] = min_tmp;
}
return a[n];
}
解法二:最短路径算法
问题转化为搜索节点n到节点0的最短路径,当两个节点差值为完全平方数时,节点间存在一条路径,路径长度均为1。
int BFSfunc(int n)
{
if (n<=0)
return -1;
queue<pair<int, int>> q;
q.push(make_pair(n, 0));
while (!q.empty())
{
int num = q.front().first;
int step = q.front().second;
q.pop();
if (num == 0)
{
return step;
}
for (auto i = 1; i*i <= num;++i)
{
q.push(make_pair(num - i*i, step + 1));
}
}
return -1;
}
改进:使用记录表,避免重复的入队
int BFSfunc(int n)
{
if (n<=0)
return -1;
queue<pair<int, int>> q;
q.push(make_pair(n, 0));
vector<char> visited(n+1, 0);
visited[n] = 1;
int tmp;
while (!q.empty())
{
int num = q.front().first;
int step = q.front().second;
q.pop();
if (num == 0)
{
return step;
}
for (auto i = 1; i*i <= num;++i)
{
tmp = num - i*i;
if (visited[tmp])
{
continue;
}
q.push(make_pair( tmp, step + 1));
visited[tmp] = 1;
}
}
return -1;
}