差分约束系统
如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如
xj−xi≤bk (i,j∈[1,n],k∈[1,m])(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。
观察
xj−xi≤bk,会发现它类似最短路中的三角不等d[v]≤d[u]+w[u,v],即d[v]−d[u]≤w[u,v]。因此,以每个变量xi为结点,对于约束条件xj−xi<=bk,连接(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终d[i]即为一组可行解。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define INF 0x7f7f7f
using namespace std;
const int MAXN = 1000+10;
struct Edge{
int sta,end,w;
Edge() = default;
Edge(int s,int e,int wi){
sta = s;end = e;w = wi;
}
};
vector <Edge> edge;
int N,ML,MD;
int Dis[MAXN];
inline void Init(){
int sta,end,w;
scanf("%d %d %d",&N,&ML,&MD);
for(auto i = 0;i < ML;++i){
scanf("%d %d %d",&sta,&end,&w);
edge.push_back(Edge(sta,end,w));
}
for(auto i = 0;i < MD;++i){
scanf("%d %d %d",&sta,&end,&w);
edge.push_back(Edge(end,sta,-w));
}
for(auto i = 2;i <= N;++i) //隐藏的d[i+1] - d[i] >=0
edge.push_back(Edge(i,i-1,0));
for(auto i = 1;i <= N;++i)
if(i == 1)
Dis[i] = 0;
else
Dis[i] = INF;
return;
}
inline void Bellman_Ford(){
for(auto k = 0;k < N-1;++k)
for(auto i = 0;i < edge.size();++i)
if (Dis[edge[i].end] > Dis[edge[i].sta] + edge[i].w ) {
Dis[edge[i].end] = Dis[edge[i].sta] + edge[i].w;
}
bool flag_nloop = false;
for(auto i = 0;i < edge.size();++i) //检查每条边是否还可以优化如果可以就是存在负权回路
if(Dis[edge[i].end] > Dis[edge[i].sta]+ edge[i].w){
flag_nloop = true;
break;
}
if(flag_nloop)
printf("-1\n");
else if(Dis[N] == INF)
printf("-2\n");
else
printf("%d\n",Dis[N]);
return;
}
int main()
{
Init();
Bellman_Ford();
return 0;
}