【UOJ#32】【UR #2】跳蚤公路(最短路)

博客围绕【UOJ#32】【UR #2】跳蚤公路的最短路问题展开。主要探讨是否存在负环,可通过维护路径上和\(x\)相关内容,用\(Floyd\)在\(O(n^5)\)复杂度求解。还可用\(Bellman - Ford\)算法检测负环,拓展为\(f[t][v][k]\)表示特定条件下最短路,进而求解\(x\)范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【UOJ#32】【UR #2】跳蚤公路(最短路)

题面

UOJ

题解

不难发现要求的就是是否存在负环。也就是我们只需要找到所有的负的简单环,很容易就可以想到维护路径上和\(x\)相关的内容,即维护一下\(u\)\(v\)路径上,含有\(kx\)的路径的最小的\(b\)。这个可以用\(Floyd\)\(O(n^5)\)的复杂度中求解。这样子我们用\(f[u][u][k]\)就知道了一个包含了\(u\)的,且\(x\)系数为\(k\)的最小的环,求出其负环的值域范围,接着其能够到达的所有点都会收到这个负环的限制。
我们的主要目的是找出简单负环,找负环可以用\(Bellman-Ford\)算法,设\(f[t][v]\)表示从\(1\)号点开始走不超过\(t\)步,到达\(v\)的最短路。因为最短路是简单路径,不会有重复点,所谓\(f[t-1][v]=f[t][v]\)。否则如果不等必定存在负环。
注意这个只能检测负环是否存在,我们还要考虑负环会造成的影响,如果一个点\(f[t][v]<f[t-1][v]\),证明这个点受到了负环的影响,同理其所有能够到达的点也能够受到负环的影响。
那么我们把这个想法拓展一步,变为\(f[t][v][k]\),表示走了\(t\)步,到\(v\)\(x\)的系数为\(k\)的最短路。
那么如果存在负环,就要满足:
\[\min\{kx+f[n][v][k]\}\ge \min\{jx+f[n-1][v][j]\}\]
那么只需要把这个数组搞出来,然后就可以解\(x\)范围了。

窝代码是抄的。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 105
#define pi pair<ll,ll>
#define f(i,j,k) f[i][j][k+105]
const ll inf=1e18;
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Line{int u,v,w,k;}e[MAX*MAX];int cnt=1;
inline void Add(int u,int v,int w,int k){e[cnt++]=(Line){u,v,w,k};}
int g[MAX][MAX];ll f[MAX][MAX][MAX<<1];
vector<pi> vec[MAX],S;
int n,m;
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;++i)
    {
        int u=read(),v=read(),w=read(),k=read();
        Add(u,v,w,k);g[u][v]=1;
    }
    for(int i=1;i<=n;++i)g[i][i]=1;
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                g[i][j]|=g[i][k]&g[k][j];
    for(int i=0;i<=n;++i)
        for(int j=1;j<=n;++j)
            for(int k=-n;k<=n;++k)
                f(i,j,k)=inf;
    f(0,1,0)=0;
    for(int i=1;i<=n;++i)
    {
        memcpy(f[i],f[i-1],sizeof(f[i]));
        for(int j=1;j<=m;++j)
        {
            int u=e[j].u,v=e[j].v,w=e[j].w,s=e[j].k;
            for(int k=-n;k<=n;++k)
                if(f(i-1,u,k)<inf)
                    f(i,v,k+s)=min(f(i,v,k+s),f(i-1,u,k)+w);
        }
    }
    for(int i=1;i<=n;++i)
        for(int k=-n;k<=n;++k)
            if(f(n,i,k)!=inf)
            {
                ll l=-inf,r=inf;bool fl=false;
                for(int j=-n;j<=n;++j)
                    if(f(n-1,i,j)!=inf)
                    {
                        if(k>j)r=min(r,(ll)ceil(1.0*(f(n-1,i,j)-f(n,i,k))/(k-j)));
                        else if(k<j)l=max(l,(ll)floor(1.0*(f(n-1,i,j)-f(n,i,k))/(k-j)));
                        else if(f(n,i,k)>=f(n-1,i,j)){fl=true;break;}
                    }
                if(!fl&&l<r)vec[i].push_back(make_pair(l,r));
            }
    for(int i=1;i<=n;++i)
    {
        S.clear();
        for(int j=1;j<=n;++j)
            if(g[1][j]&&g[j][i])
                for(auto p:vec[j])S.push_back(p);
        sort(S.begin(),S.end());
        ll l=inf,r=-inf,lst=-inf;
        bool fl=false;
        for(int j=0,len=S.size();j<len;++j)
        {
            if(!j&&S[j].first>-inf)
            {
                l=-inf;r=S[j].first;
                fl=true;break;
            }
            if(lst!=-inf&&lst<=S[j].first)
            {
                l=lst;r=S[j].first;
                fl=true;break;
            }
            lst=max(lst,S[j].second);
        }
        if(!fl&&lst<inf)l=lst,r=inf;
        if(l==-inf||r==inf||!S.size())puts("-1");
        else printf("%lld\n",max(0ll,r-l+1));
    }
    return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/11047191.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值