spfa+差分约束系统(C - House Man HDU - 3440 )+对差分约束系统的初步理解

本文探讨了一个涉及楼层跳跃的路径优化问题,利用差分约束系统建立不等式,通过SPFA算法求解最大差值。关键在于根据楼层高度调整楼间距离,确保按高度递增顺序跳跃的同时,计算首尾楼间的最远距离。

题目链接:https://cn.vjudge.net/contest/276233#problem/C

题目大意:有n层楼,给你每个楼的高度,和这个人单次的最大跳跃距离m,两个楼之间的距离最小是1,但是楼和楼之间的距离是能够调整的,现在有一个人,要从最矮的楼开始跳,每一次跳到比当前的楼高的楼上,然后问你在将所有的楼都走一遍的基础上,从第一个楼到最后一个楼之间的最远距离是多少?

思路:使用差分约束系统的相关知识, 我们可以建立如下不等式。

1,当相邻的时候,限制posA-posB>=1,也就是posB-posA<=-1。

2,当按照高度依次建立边的时候,我们就限制posA-posB<=m。这样的根据这两个式子就可以建立图了。

注意点:我们在建立相邻点的时候,是按照从小到大进行建边的,所以在对于第二种情况的时候,我们应该是先判断两个位置的大小,再去建边。

对差分约束系统的初步理解:如果是和spfa有关的话,具体就是建立不等式,然后如果求最大差值的话,我们直接将变建立成这两个点的最大差值就可以了。然后在跑最短路的过程中,就是找满足从posA到posB的所有不等式当中的最小的哪一个,因为求出来的值是要满足这两个点的所有不等式的。

AC代码:

#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
# define inf 1ll<<60
const int maxn = 1000+100;
const int maxedge= 1000000+10;
int n;
ll m;
int num,head[maxn];
ll dis[maxn];
int out[maxn],vis[maxn];
struct node
{
    int fr;
    int to;
    ll cost;
    int nex;
} edge[maxedge];
struct point
{
    int num;
    int id;
} po[maxn];
bool cmp(point t1,point t2)
{
    return t1.num<t2.num;
}
void init()
{
    for(int i=0; i<=n; i++)
    {
        head[i]=-1;
        out[i]=0;
        vis[i]=0;
        dis[i]=inf;
    }
    num=0;
}
void addedge(int fr,int to,ll cost)
{
    edge[num].to=to;
    edge[num].cost=cost;
    edge[num].nex=head[fr];
    head[fr]=num++;
}
ll spfa(int st,int ed)
{
    dis[st]=0;
    vis[st]=1;
    queue<int>q;
    q.push(st);
    while(!q.empty())
    {
        int tmp=q.front();
        q.pop();
        vis[tmp]=0;
        out[tmp]++;
        if(out[tmp]>n)
            return -1;
        for(int i=head[tmp]; i!=-1; i=edge[i].nex)
        {
            int u=edge[i].to;
            if(dis[u]>dis[tmp]+edge[i].cost)
            {
                dis[u]=dis[tmp]+edge[i].cost;
                if(vis[u])
                    continue;
                vis[u]=1;
                q.push(u);
            }
        }
    }
    return dis[ed];
}
int main()
{
    int T;
    scanf("%d",&T);
    int Case=0;
    while(T--)
    {
        scanf("%d %lld",&n,&m);
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&po[i].num);
            po[i].id=i;
        }
        for(int i=1; i<n; i++)
        {
            addedge(i+1,i,-1);
        }
        sort(po+1,po+n+1,cmp);
        for(int i=1; i<n; i++)
        {
            int u=po[i+1].id;
            int v=po[i].id;
            if(u>v)
                swap(u,v);
            addedge(u,v,m);
        }
        int t1=po[1].id;
        int t2=po[n].id;
        if(t1>t2)
            swap(t1,t2);
        ll ans=spfa(t1,t2);
        printf("Case %d: %lld\n",++Case,ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值