(1)求不等式组的可行解

 可以把差分约束转化为单元最短路问题,那么要寻找的源点就需要满足:从源点出发,一定可以走到所有的边

步骤:

1. 现将每个不等式xi<=xj+c,转化为一条从xj走到xi,长度为ck的一条边
2. 找一个超级源点,使得该源点一定可以遍历到所有边
3. 从原点求一遍单元最短路
       结果1:如果存在负环,则原不等式组一定无解
       结果2:如果没有负环,则dist[i]就是原不等式组的一个可行解

image.png
(2)求最大值和最小值

 结论:如果求的是最小值,则应该求的是最长路;如果求的是最大值,则应该求的是最短路;
 问题1:如何转化xi >= c,其中c是一个常数
 方法:建立一个超级源点0,然后0->i,长度为c即可
 以求xi的最大值为例:求所有从xi出发,构成不等式链 xi<=xj+c1<=xk+c2+c1<=......<=c1+c2+....所计算出的上界,最终xi的最大值等于所有上界的最小值。

Acwing 1169. 糖果

image.png

输入样例:

5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1

输出样例:
11

#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <queue>


using namespace std;
const int N = 100010, M = 100010;
int n , m;
int head[N],to[M],nex[M],w[M],idx;
void add(int a,int b,int c)
{
    to[idx]=b;
    w[idx]=c;
    nex[idx]=head[a];
    head[a]=idx++;
}
bool st[N];
long long int dis[N];
int cnt[N];
int q[N];
bool SPFA()
{
    memset(st,0,sizeof(st));
    memset(dis,-0x3f,sizeof(dis));//求最大路,所以初始位负无穷
    memset(cnt,0,sizeof(cnt));
    int t=1;
    q[0] = 0;
    dis[0]=0;
    st[0]=true;
    while(t!=0)
    {
        int top=q[--t];
        st[top]=false;
        for(int i=head[top];~i;i=nex[i])
        {
            int j=to[i];
            int l=w[i];
            if(dis[j]<dis[top]+l)
            {
                dis[j]=dis[top]+l;
                cnt[j]=cnt[top]+1;
                if(cnt[j]>=n+1)
                {
                    return false;//有负环
                }
                if(!st[j])
                {
                    q[t++]=j;
                    st[j]=true;
                }
            }
        }
    }
    return true;
}


int main()
{
    scanf("%d %d",&n,&m);
    memset(head,-1,sizeof(head));
    while (m--)
    {
        int x,a,b;
        scanf("%d %d %d",&x,&a,&b);
        if(x==1)
        {
            add(a,b,0);
            add(b,a,0);
        }
        else if(x==2)
        {
            add(a,b,1);
        }
        else if(x==3)
        {
            add(b,a,0);
        }
        else if(x==4)
        {
            add(b,a,1);
        }
        else
        {
            add(a,b,0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        add(0,i,1);//至少有一个糖果
    }
    if(!SPFA())//有负环,不满足不等式
    {
        cout<<"-1"<<endl;
    }
    else
    {
        long long int ret=0;
        for(int i=1;i<=n;i++)
        {
            ret+=dis[i];
        }
        printf("%lld\n",ret);
    }
    return 0;
}

Acwing 362. 区间
image.png

image.png

分析过程:
image.png

#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;
const int N = 50010, M = 150010;
int n;
int h[N], e[M], w[M], nex[M], idx;
int dist[N];
int q[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b;
    w[idx] = c;
    nex[idx] = h[a];
    h[a] = idx++;
}
void SPFA()
{
    memset(dist, -0x3f, sizeof dist);
    dist[0] = 0;
    st[0] = true;
    int hh = 0, tt = 1;
    q[0] = 0;
    while (hh != tt)
    {
        int t = q[hh ++ ];
        if (hh == N) hh = 0;
        st[t] = false;
        for (int i = h[t]; ~i; i = nex[i])
        {
            int j = e[i];
            if (dist[j] < dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if (!st[j])
                {
                    q[tt ++ ] = j;
                    if (tt == N) tt = 0;
                    st[j] = true;
                }
            }
        }
    }
}

int main()
{
    scanf("%d", &n);
    memset(h, -1, sizeof h);
    for (int i = 1; i < N; i ++ )
    {
        add(i - 1, i, 0);
        add(i, i - 1, -1);
    }
    for (int i = 0; i < n; i ++ )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        a ++, b ++ ;
        add(a - 1, b, c);
    }
    SPFA();
    printf("%d\n", dist[50001]);
    return 0;
}

拾柒
1 声望1 粉丝

引用和评论

0 条评论