(1)求不等式组的可行解
可以把差分约束转化为单元最短路问题,那么要寻找的源点就需要满足:从源点出发,一定可以走到所有的边
步骤:
1. 现将每个不等式xi<=xj+c,转化为一条从xj走到xi,长度为ck的一条边
2. 找一个超级源点,使得该源点一定可以遍历到所有边
3. 从原点求一遍单元最短路
结果1:如果存在负环,则原不等式组一定无解
结果2:如果没有负环,则dist[i]就是原不等式组的一个可行解
(2)求最大值和最小值
结论:如果求的是最小值,则应该求的是最长路;如果求的是最大值,则应该求的是最短路;
问题1:如何转化xi >= c,其中c是一个常数
方法:建立一个超级源点0,然后0->i,长度为c即可
以求xi的最大值为例:求所有从xi出发,构成不等式链 xi<=xj+c1<=xk+c2+c1<=......<=c1+c2+....所计算出的上界,最终xi的最大值等于所有上界的最小值。
Acwing 1169. 糖果
输入样例:
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. 区间
分析过程:
#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;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。