ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

差分约束 利用图论的不等式求变量

2022-05-16 19:32:25  阅读:198  来源: 互联网

标签:图论 dist idx 不等式 int tt 差分 st add


求满足多个不等式组的元素

=表示+1
(1)求不等式组的可行解
(2)!!源点需要满足的条件 从源点出发,一定可以走到所有的边!!!
存在负环说明无解 正环有解
1.先找每个不等式 xi<= xj+ck 转化为已调配从xi到xj长度为ck的一条边
2.找一个超级源点 是的该源点一定可以遍历到所有边
3.从源点求一次单源最短路
结果1:入股存在
结果2:

(3) 求最大最小值 一定是求个每个变量的关系
求最小值 应该求最长路
求最大值 应该求最短路
一定有个绝对关系 作为最小值 xi>=0 转化为 xi>=c c是一个常数 xi<=c 方法 建立超级源点 对每个i连接一个长度为c的边
求xi的最大值 就是0到xi的最短路

求最小值 ->最长路 memset负无穷 ->大于号

https://www.acwing.com/problem/content/1171/
A=B <-> a>=b && b>=a
a<b <-> b>=a+1 a到b连一个权为1的边
a>=b <-> a>=b
a>b <-> a>=b+1
a<=b <-> b>=a
x>=1 <-> xi>=x+1

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, M = 300010;

int n, m;
int h[N], e[M], w[M], ne[M], idx;
LL dist[N];
int q[N], cnt[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

bool spfa()
{
    int hh = 0, tt = 1;
    memset(dist, -0x3f, sizeof dist);
    dist[0] = 0;
    q[0] = 0;
    st[0] = true;

    while (hh != tt)
    {
        int t = q[ -- tt];
        st[t] = false;

        for (int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if (dist[j] < dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                cnt[j] = cnt[t] + 1;
                if (cnt[j] >= n + 1) return false;//因为这里是n+1个点(超级源点) 所以需要+1
                if (!st[j])
                {
                    q[tt ++ ] = j;
                    st[j] = true;
                }
            }
        }
    }

    return true;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    while (m -- )
    {
        int x, a, b;
        scanf("%d%d%d", &x, &a, &b);
        if (x == 1) add(b, a, 0), add(a, b, 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);//每个点都有连接一个1 表示至少一个糖果

    if (!spfa()) puts("-1");
    else
    {
        LL res = 0;
        for (int i = 1; i <= n; i ++ ) res += dist[i];
        printf("%lld\n", res);
    }

    return 0;
}


求最长路

前缀和:

si: 集合从[1,n]中选择整数的个数.
1≤i≤50001. 下面用V=50001V=50001.

s0=0. 符合定义, 且作为求最小值的明确下界.

问题转换为求满足条件的sVsV最小值. 求最小值用最长路算法求解, 从原题中建立≥≥的关系.

不等式关系的建立:

si≥si−1,1≤i≤V: 前缀和含义的限制.

si−si−1≤1,1≤i≤V
si−1≥si−1: 保证整数i最多选一次.

区间[a,b]至少选c个: sb−sa−1≥c --> sb≥sa−1+c

转换为最长路问题:

将si作为顶点, 每个不等式关系作为有向边建图.

源点: 需要满足从源点出发能到达所有边. 考虑不等式关系si≥si−1,1≤i≤V 相当于有向边:

作者:代码改变头发
链接:https://www.acwing.com/solution/content/80472/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

#include <cstring>
#include <iostream>

using namespace std;

const int V = 50001, N = V + 10, M = 50000 * 3 + 10;

int n;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], q[N]; bool st[N]; 

void add(int u, int v, int c)
{
    e[idx] = v, w[idx] = c, ne[idx] = h[u], h[u] = idx ++;
}

void spfa()
{
    memset(dist, -0x3f, sizeof dist);
    dist[0] = 0;
    int hh = 0, tt = 0;
    q[tt ++] = 0; st[0] = true;

    while( hh != tt )
    {
        int u = q[hh ++];
        if( hh == N )   hh = 0;

        st[u] = false;

        for( int i = h[u]; ~i; i = ne[i] )
        {
            int v = e[i];
            if( dist[v] < dist[u] + w[i] )
            {
                dist[v] = dist[u] + w[i];
                if( !st[v] )
                {
                    st[v] = true;
                    q[tt ++] = v;
                    if( tt == N )   tt = 0;
                }
            }
        }
    }
}

int main()
{
    cin >> n;

    memset(h, -1, sizeof h);
    for( int i = 1; i <= V; i ++ )
    {
        add(i - 1, i, 0); //s(i) >= s(i-1) + 0
        add(i, i - 1, -1); //s(i - 1) >= s(i) - 1
    }

    for( int i = 0; i < n; i ++ )
    {
        int a, b, c;
        cin >> a >> b >> c;
        a ++, b ++; // + bias
        add(a - 1, b, c); //s(b) >= s(a-1) + c
    }

    spfa();
    cout << dist[V] << endl; //s(50001) 

    return 0;
}


标签:图论,dist,idx,不等式,int,tt,差分,st,add
来源: https://www.cnblogs.com/liang302/p/16278211.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有