差分约束 利用图论的不等式求变量
作者:互联网
求满足多个不等式组的元素
=表示+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