广东省赛补题_J
lijie
从哪到哪,并且需要最值,考虑bfs
应用bfs:扩展的时候权值如果都是一样的,那么一定可以用bfs,反之不可以用。
bfs重要特性就是,可以最优到最优,原理就是:
next=最优+权值,而所有状态权值都是一样的,所以只要最优,那么就可push进队。
在本题中,权值是1,也就是每扩展一次,步数+1。
对哪个状态来说,只要扩展一次,步数都是+1,所以权值是相同的,为1。
ps:对于迷宫找出路问题,每扩展一步,步数+1,是一个道理。
但是bfs对于有权值的图,就不能用了,因为:next=最优+权值,各个状态权值不同,所以仅根据当前最优得不到下一个状态最优
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int a[400];
int d[N]; //到i最少需要几步
void bfs()
{
for(int i=1;i<=320;i++) //预处理
a[i]=i*i;
queue<int> q; //到达的位置
for(int i=1;i<=320;i++) //queue初始化
if(a[i]<=100000)
{
q.push(a[i]);
d[a[i]]=1;
}
//bfs 每次都用最优的点走平方数,把这些点都走遍(1~100000),
while(q.size())
{
int t=q.front();
q.pop();
for(int i=1;i<=320;i++) //在图中相当于上下左右四个方向
{
int x=a[i]+t; //在t点通过+a[i]所能到达的位置
if(x>100000) break;
if(!d[x]) //如果没被标记说明是首次到达,那么一定是最优的
{
d[x]=d[t]+1;
q.push(x);
}
}
for(int i=1;i<=320;i++)
{
int x=t-a[i]; //在t点通过-a[i]所能到达的位置
if(x<0) break;
if(!d[x])
{
d[x]=d[t]+1;
q.push(x);
}
}
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
bfs(); //预处理
int q,x;
cin>>q;
while(q--)
{
cin>>x;
cout<<d[x]<<endl;
}
return 0;
}
**
解法二
**
完全背包,把数轴想象成一个容量为100000的背包。
使用一个平方数,就把每个容量(1-100000)去松弛一遍。
因为每个平方数是无尽用的,所以是完全的。
ps:完全背包为什么从前向后循环?
01背包用的都是没被更新过的包…
从后往前的话,前面的都是当前物品还没用过的包
完全背包用的都是被更新过的包 …
从前往后的话,前面用了,后面还能用
#include<bits/stdc++.h>
using namespace std;
int q,d;
const int N=1e5+10;
int dp[N];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
vector<int> a;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i*i<=100000;i++)
a.push_back(i*i),dp[i*i]=1;
for(int i=0;i<a.size();i++)
{
for(int j=a[i];j<=100000;j++) dp[j]=min(dp[j],dp[j-a[i]]+1);
for(int j=1;j+a[i]<=100000;j++) dp[j]=min(dp[j],dp[j+a[i]]+1);
}
cin>>q;
while(q--)
{
cin>>d;
cout<<dp[d]<<endl;
}
return 0;
}