差分约束 学习笔记

给你一个含有$n$个未知数$m$个不等式的不等式组,求满足此不等式组的一组解。

-----------------------

我们拿一个不等式举例:$X_{i}-X_{j}\leq C_{k}$。

这和最短路算法里的松弛操作比较像:dis[to]>=dis[now]+edge[i].dis。所以我们可以将其转化为图:从$j$点到$i$点连一条长度为$d$的边。

有时候我们可以建立一个超级源点,来求得这组不等式的最小(大)解。即从$0$点到$i$点连一条长度为$0$的边,从$0$点跑最短路即可。

 

记得要判定图里是否有环,因为如果图里有环这组不等式是无解的。

 

给一道模板题:题目描述

--------------------------------------------

差分约束裸题,直接上代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,head[50005],cnt,u,v,d,c[50005];
int vis[50005],dis[50005];
struct node
{
    int next,to,dis;
}edge[50005];
void add(int from,int to,int dis)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    edge[cnt].dis=dis;
    head[from]=cnt;
}
void spfa(int x)
{
    queue<int> q;
    memset(dis,0x3f3f3f3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(c,0,sizeof(c));
    q.push(x);dis[x]=0;vis[x]=1;
    while(!q.empty())
    {
        int now=q.front();q.pop();vis[now]=0;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (dis[to]>dis[now]+edge[i].dis)
            {
                dis[to]=dis[now]+edge[i].dis;
                c[to]=c[now]+1;
                if (c[to]>=n)
                {
                    cout<<"NO";
                    exit(0);
                }
                if (!vis[to])
                {
                    q.push(to);
                    vis[to]=1;
                }
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for (int i=1;i<=m;i++)
        cin>>u>>v>>d,add(v,u,d);
    for (int i=1;i<=n;i++)
        add(0,i,0);
    spfa(0);

    for (int i=1;i<=n;i++) cout<<dis[i]<<" ";
    return 0;
}

 差分约束的条件不会一眼能看出来,我们要学会转化。

题目:LMX的攻城游戏

题目大意:给定一段长度为$n$的数列,有$m$个条件。每个条件给定一个三元组$a,b,c$,表示从$a$到$b$至少有$c$。问序列和最小是多少。

---------------------------------

题目转化:$S_{b}-S_{a-1}\leq c$ 。

其实题目里面还有一个隐藏条件,即$S_{i+1}-S_{i}\leq 1$。

有了这些条件,这道题就可以转化为差分约束处理了。

代码:

#include<bits/stdc++.h>
using namespace std;
int vis[100005],dis[100005],n,m;
int head[500005],cnt;
struct node{
    int next,to,dis;
}edge[500005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void add(int from,int to,int dis)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    edge[cnt].dis=dis;
    head[from]=cnt;
}
void spfa()
{
    queue<int> q;
    dis[0]=0;vis[0]=1;q.push(0);
    while(!q.empty())
    {
        int now=q.front();vis[now]=0;q.pop();
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (dis[to]>dis[now]+edge[i].dis)
            {
                dis[to]=dis[now]+edge[i].dis;
                if (!vis[to]){
                    q.push(to);
                    vis[to]=1;
                }
            }
        }
    }
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=n;i++) dis[i]=i;
    for (int i=1;i<=m;i++)
    {
        int u=read(),v=read(),d=read();
        add(u-1,v,-d);
    }
    for (int i=1;i<=n;i++) add(i,i-1,1),add(i-1,i,0);
    spfa();
    printf("%d",-dis[n]);
    return 0;
}

 

posted @ 2020-03-14 22:03  我亦如此向往  阅读(163)  评论(0编辑  收藏  举报