负环与差分约束

负环

负环的判定比较简单,直接用spfa即可。在求负环或是正环时要注意一个点:
要提前将所有点入队并更新其dist值为0。为什么要这么做呢?
1.任意挑选的起点有可能与环不连通,所以要加入虚拟原点s,并将其与所有点相连
2.初值置为0不会影响最短路的长度
例题1:AcWing361.观光奶牛
这题比较简单,考虑用0/1分数规划求解,代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1005,M=5005;
const double eps=1e-4;
int n,m;
int head[N],to[M],ne[M],idx;
double w[M],f[N];
struct Edge{
    int x,y;
    double z;
}edge[M];
void add(int x,int y,double z){
    ne[++idx]=head[x];
    to[idx]=y;
    w[idx]=z;
    head[x]=idx;
}
queue<int> q;
double dist[N];
bool st[N];
int cnt[N];
bool spfa(){
    memset(cnt,0,sizeof cnt);
    memset(st,false,sizeof st);
    for(int i=1;i<=n;i++){
        q.push(i);
        dist[i]=0.0;
    }
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=head[t];i;i=ne[i]){
            int j=to[i];
            if(dist[j]>dist[t]+w[i]){
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return true;
                if(!st[j]){
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
bool check(double mid){
    memset(head,0,sizeof head);
    memset(to,0,sizeof to);
    memset(ne,0,sizeof ne);
    idx=0;
    for(int i=1;i<=m;i++){
        int x=edge[i].x,y=edge[i].y;
        double z=mid*edge[i].z-f[x];
        add(x,y,z);
    }
    return spfa();
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>f[i];
    for(int i=1;i<=m;i++){
        int x,y;
        double z;
        cin>>x>>y>>z;
        edge[i]={x,y,z};
    }
    double l=0,r=1e6;
    while(r-l>eps){
        double mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%.2lf",l);
    return 0;
}

扩展设问:求该比值的最小值

差分约束

这个算法常用于解决多元一次不等式组(但前提是每个不等式都要可以整理成xi-xj ≤ \leq c的形式)。其难点在于不等关系的寻找以及一些对于未知数隐含的限制条件。
例题1:AcWing 362.区间
这个题目还是很有思维量。首先想到将区间与个数的不等关系转化成两个未知数的差与另一个常数之间的不等关系,这便联想到前缀和。即设xi为值为i的数有多少个,sumi为x数组的前缀和。那么不等关系就巧妙地转化为了sumb-suma-1 ≥ \geq c。然而到这里还没完,对于每个sumi还有限制,首先它自身大小至多为1(集合内元素不可重复),且sumi ≥ \geq sumi-1代码如下:

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=50005;
int head[N],to[3*N],ne[3*N],w[3*N],idx;
void add(int x,int y,int z){
    ne[++idx]=head[x];
    to[idx]=y;
    w[idx]=z;
    head[x]=idx;
}
int dist[N];
bool st[N];
void spfa(){
    queue<int> q;
    q.push(0);
    memset(dist,-0x3f,sizeof dist);
    dist[0]=0;
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=head[t];i;i=ne[i]){
            int j=to[i];
            if(dist[j]<dist[t]+w[i]){
                dist[j]=dist[t]+w[i];
                if(!st[j]){
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=50001;i++){
        add(i-1,i,0);
        add(i,i-1,-1);
    }
    for(int i=1;i<=n;i++){
        int a,b,c;
        cin>>a>>b>>c;
        a++,b++;
        add(a-1,b,c);
    }
    spfa();
    cout<<dist[50001]<<endl;
    return 0;
}

一个比较重要的补充点:
差分约束不是可以随便转化求最长路或者最短路的,要根据题意。本题要求最小值。那么我们直到ans ≥ \geq m。对于一堆这样形式的不等式,我们必然会取m的最大值作为ans的最小值,也就是求最长路。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值