广东省赛补题_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;
}

 
posted @ 2021-08-04 18:40  DuJunlong  阅读(4)  评论(0编辑  收藏  举报  来源