蓝桥杯,省赛,最大数,环境治理

文章讨论了如何使用动态规划解决跳跃游戏问题,通过Floyd算法结合二分查找策略优化多源最短路径中的灰尘度管理,以找到最少的改善天数以满足所有边的灰尘度限制。
摘要由CSDN通过智能技术生成
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
//根本就不是dp
using namespace std;
const int N = 10010,inf=0x3f3f3f3f;
int n;
int a[N],f[N];
bool is_prime(int x)//质数的判断
{
    for (int i = 2; i < x / i; ++ i )
        if (x % i == 0)
            return false;
    return true;
}

int d_prime(int x)//遍历所有因子数
{
    for (int i = 2; i <= x; ++ i )
        if (x % i == 0 && is_prime(i))//为x的因子同时为质数,由每次于从2开始便得到最小因子
            return i;
    return 1;
}
int main() {
     cin>>n;
     for(int i=1;i<=n;i++) cin>>a[i];
     memset(f,-inf,sizeof(f));//初始化
     f[1]=a[1];
     for(int i=1;i<=n;i++){
       int j=d_prime(n-i);//从当前位置所能跳到的最远位置i——i+1到i+d_prime(n-i)
       for(int k=i+1;k<=i+j;k++){  //遍历所有的可能跳到的位置
        if(f[k] == -inf) f[k] = a[k] + f[i];//如果之前为经过,便直接f[i]+a[k];
        else f[k]=max(f[k],f[i]+a[k]);
        }
     }
     cout<<f[n];
    return 0;
}

这段代码是一个动态规划的例子,用于解决跳跃游戏问题。该问题描述为:给定一个长度为n的数组a,每个元素代表从当前位置最多能向后跳的步数,求从第一个位置开始,最少需要跳几次能够跳到最后一个位置。

该问题可以使用动态规划的思想来解决。具体来说,我们可以定义状态f[i]表示从第一个位置跳到第i个位置所需的最少跳跃次数。则状态转移方程为:

f[i] = min{f[j]} + 1 (i-j<=a[j])

其中,j是i之前的位置,a[j]是从j位置最多能向后跳的步数。这个状态转移方程的意思是,我们从i之前的位置j跳到i位置,需要跳跃的次数为f[j]+1。而j的取值范围是i之前的所有位置中,能够跳到i位置的位置。也就是说,如果j位置能够跳到i位置,那么从j位置跳到i位置所需的跳跃次数就是f[j]+1。

在这段代码中,我们可以看到,状态f[i]的定义与上述状态定义略有不同,它表示从第一个位置跳到第i个位置所能获得的最大分数。而状态转移方程也有所不同,它是:

f[k] = max{f[i]+a[k]} (i+1<=k<=i+d_prime(n-i))

其中,d_prime(n-i)表示从第i个位置最多能向后跳的步数。这个状态转移方程的意思是,我们从i位置跳到k位置,所能获得的最大分数是f[i]+a[k]。而k的取值范围是i+1到i+d_prime(n-i),也就是说,我们只能跳到i之后的位置,并且最多只能跳d_prime(n-i)步。

最后,我们输出f[n]即可,它表示从第一个位置跳到最后一个位置所能获得的最大分数。

环境治理

//多源最短路径Floyd算法+二分答案
//核心在于用二分法枚举所有可能的方案(改善天数)
//改善mid天,相当于改善完整的mid/n轮+mid%n天,编号为1~mid%n的结点的灰尘度可以多减1
//填写dist数组后跑一遍Floyd算法验证当前P值是否小于等于Q,继续二分即可 
#include <bits/stdc++.h>

using namespace std;

typedef  long long ll;

const int N=120;

ll n,Q;
ll graph[N][N];//图 
ll dist[N][N];//dist[i][j]存储i->j的最短距离 
ll limit[N][N];//limit[i][j]存储i->j的灰尘度下限 

ll Floyd()//Floyd算法求任意两点间的最短路径,返回所有最短路径的和(当前的P值) 
{
    ll res=0;
    for(int k=1;k<=n;k++)//模板 
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
            } 
        }
    }
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)res+=dist[i][j];
    }
    return res;
}

bool check(ll mid)//验证改善mid天,能否使得灰尘度小于等于Q 
{
    memcpy(dist,graph,sizeof(graph));//将原图复制给dist(细节,若本次check为false,下次还要使用旧图) 
    ll circle=mid/n;//改善mid天,相当于改善了完整的circle轮 
    ll mod=mid%n;//还剩下mod天,给1~mod号点单独改善 
    for(int i=1;i<=n;i++)//枚举所有的结点对(i,j) 
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)continue;//不是道路
            //若i与j不重合,存在i->j的边
            //若i的编号小于等于mod,说明改善了circle轮后还能单独改善一天,
            //故灰尘度为dist[i][j]-circle-1,但不能小于limit[i][j] 
            if(i<=mod)dist[i][j]=max(limit[i][j],dist[i][j]-circle-1);
            //若i的编号超出mod,说明只能恰好改善circle轮,灰尘度为dist[i][j]-circle 
            else dist[i][j]=max(limit[i][j],dist[i][j]-circle);
            dist[j][i]=dist[i][j];//双向道路,j->i的灰尘度也随之改善 
        }
    }
    
    ll d=Floyd();//对于更新后的dist数组,重新跑Floyd算法并求解当前P值 
    return d<=Q;//P值不大于Q,说明该方案可行 
}

int main()
{
    scanf("%lld%lld",&n,&Q);
    for(int i=1;i<=n;i++)//输入i*j条道路的灰尘度(邻接矩阵存储) 
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%lld",&graph[i][j]);    
        }    
    }    
    for(int i=1;i<=n;i++)//输入每条道路的灰尘度下限值 
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%lld",&limit[i][j]);
            dist[i][j]=limit[i][j];
        }
    }
    if(Floyd()>Q)//用下限limit先跑一遍Floyd算法,若P值已经大于Q,说明根本无法改善 
    {
        printf("-1\n");
        return 0;
    }
    ll left=0,right=1e9+1;//开始二分 
    while(left<=right)
    {
        ll mid=(left+right)>>1;
        if(check(mid))right=mid-1;//改善mid天可行,则缩小右边界继续试探 
        else left=mid+1;//不可行,扩大左边界 
    }
    printf("%lld\n",left);//输出即可 
    return 0;
}

这是一篇关于多源最短路径Floyd算法和二分答案的题解。Floyd算法是一种求任意两点间最短路径的算法,时间复杂度为O(n3),适用于稠密图。二分答案则是一种常用的解决最优化问题的方法,时间复杂度为O(logn),适用于单调性问题。

这段代码的主要思路是:给定一个图,每条边有一个灰尘度,每条边还有一个灰尘度下限,现在要求改善若干天,每天可以使得编号为11到mid%n的点的灰尘度减11,或者使得所有点的灰尘度减11,问最少需要改善多少天才能使得所有边的灰尘度都不大于其下限。

具体实现上,我们可以用二分法枚举改善天数mid,然后对于每个mid,我们可以用Floyd算法求出改善mid天后的所有点对之间的最短距离,然后判断是否所有边的灰尘度都不大于其下限。如果是,则说明mid天的改善方案可行,我们可以缩小右边界继续试探;否则,我们需要扩大左边界。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值