题目链接
https://www.luogu.com.cn/problem/P1260
思路
这是一道差分约束模板题。什么是差分约束?简单来说就是一组(n)元一次不等式组,每个不等式以(x_i-x_jleq k)的形式给出,求化简之后各个变量之间的关系。
可以看成图论问题,如果(x_i-x_jleq k),我们就建一条从(x_j)到(x_i)(注意顺序!!),边权为(k)的边,表示(x_j)到(x_i)的距离(leq k),
钦定一个源点,那么对任意(x_i),(x_i)需要满足从源点到(x_i)的路径代表的所有不等式,所以(x_i)的最大值就是源点到(x_i)的最短路(各个解集求交集,(x_ileq)最短路)。
比如:(left{egin{array}\x_5-x_1leq -1\{x_2-x_1<=0}\x_5-x_2leq 1 end{array}
ight.)
联立解得(x_5-x_1leq -1),就是(x_1)到(x_5)的最短路。
注意有负权边,如果有负环的话该不等式组无解(相当于套圈之后(x_ileq x_i-C)(C是某常数)),体现在spfa中就是某节点入队次数大于总点数。
但是这是针对连通图而言,如果图不连通,有的节点根本无法访问到,那就建一个超级源S,加入S到1至n号节点的n条边,边权为0。
代码
#include<cstdlib>
#include<queue>
#define db double
#define inf 0x3f3f3f3f
#define maxn (int)(1e4+10)
using namespace std;
int fst[maxn],nxt[maxn],w[maxn],to[maxn],cnt=0,dis[maxn],n,m;
int book[maxn],flag=0,num[maxn];
void add(int x,int y,int z){
w[++cnt]=z;
to[cnt]=y;
nxt[cnt]=fst[x];
fst[x]=cnt;
}
bool spfa(){
int i;
queue<int> q;
while(!q.empty()) q.pop();
for(i=1;i<=n;++i)
dis[i]=inf;
q.push(n+1);
book[n+1]=1;
while(!q.empty()){
int p=q.front();
for(i=fst[p];i;i=nxt[i]){
if(dis[p]+w[i]<dis[to[i]]){
dis[to[i]]=dis[p]+w[i];
if(!book[to[i]]){
num[to[i]]++;
if(num[to[i]]>n+1) return 0;
q.push(to[i]);
book[to[i]]=1;
}
}
}
book[p]=0;
q.pop();
}
return 1;
}
int main(){
int i,x,y,z,MIN=inf;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
add(y,x,z);
}
for(i=1;i<=n;i++){
add(n+1,i,0);
}
if(spfa()){
for(i=1;i<=n;i++)
MIN=min(MIN,dis[i]);
for(i=1;i<=n;i++)
printf("%d
",dis[i]-MIN);
}
else printf("NO SOLUTION");
// system("pause");
return 0;
}