洛谷P1993

博客探讨了差分约束系统在解决不等式组问题中的应用,通过将不等式转化为图的最长路径问题。文章指出,为确保所有条件满足,需找到路径的最小值,并介绍了如何构建图和寻找负环以判断系统的可行性。使用SPFA算法可能出现超时,而题解中提出了DFS优化的解决方案。

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

差分约束系统

我们可以把一个不等式,看做两个点和一条边,而边则是约束不等式的一个条件

距离 a - b >= c

那么 建边就是 a---c---b ,a b之间建立一条权值为 c 的边,然后我们还可以根据不等式的运算进行一部分约束

对于多个不等式组:

v(x1) - v(x2) >= c1

v(x2) - v(x3) >= c2

……

把它们加起来就会得到:v(x1) - v(xn) >= c1 + c2 + …… + cn-1

而对于所有的不等式,倘若我们满足了 >= 中的最大值,那么所有条件不也就都满足了吗

所以求v(x)-v(y)的最小值是在图上求最长路径。(摘自题解上某个巨巨的博客)

而题目中判断是否成立,也就是看一下这个差分约束系统是否存在一个矛盾,

首先所有数字大于0, 我们不妨建立一个 V(x) - 0 >= 0 把所有点和 0 连一条边就好了

只要求出所有不等式中的最小值,代表着这个系统可以被满足

但是如果光这么看,我们发现这个图就是一棵树。。没有完全连通,那么我们便在最后加一个辅助点,使得整个图变成连通的,

之后我们需要做的就是找一下整个图中的负环,因为一旦存在负环,说明这个系统内部出了问题,出现矛盾了,就不成立了,那么我们反向思路,只要找到一个正环,这道题不就有可成立的情况了吗。。

所以我们用 spfa 来跑一次求负环。。但是这道题被 卡了 tle 好几组数据。。最后看了下题解。。发现竟然 dfs 优化。。

有点玄学。。但是这道题。。非常不错。。

 

以下 是 AC 代码

 

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
#define pb push_back
inline int read()
{
    int s=0,w=1;char ch = getchar();
    while(ch<'0'||ch>'9'){if(ch == '-')w=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){s = s*10 + ch-'0';ch=getchar();}
    return w*s;
}
struct node
{
    int to,val,nxt;
}ed[maxn];
int head[maxn],tot;
inline void add(int a, int b, int v)
{
    ed[++tot].to = b;
    ed[tot].val = v;
    ed[tot].nxt = head[a];
    head[a] = tot;
}
int dis[maxn];
bool vis[maxn];
bool inque[maxn];
bool spfa(int s)
{
    inque[s] = true;
    for(int i=head[s];~i;i=ed[i].nxt)
    {
        int to = ed[i].to;
        int val = ed[i].val;
        if(!vis[to] || dis[to] < dis[s] + val)
        {
            if(inque[to])
                return false;
            vis[to] = true;
            dis[to] = dis[s] + val;
            if(!spfa(to))return false;
        }
    }
    inque[s] = false;
    return true;
}
int main()
{
    int n=read(),m=read();
    memset(head,-1,sizeof head);
    tot = 0;
    for(int i=1;i<=n;i++)
    {
        add(i, 0, 0);
        add(n+1, i, 0);
    }
    for(int i=1;i<=m;i++)
    {
        int t=read();
        if(t == 1)
        {
            int a=read(),b=read(),c=read();
            add(a, b, c);
        }
        if(t == 2)
        {
            int a=read(),b=read(),c=read();
            add(b, a, -c);
        }
        if(t == 3)
        {
            int a=read(),b=read();
            add(a, b, 0);
            add(b, a, 0);
        }
    }
    if(spfa(n+1))
        puts("Yes");
    else
        puts("No");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值