D118 最短路→差分约束 SPFA 算法 P4878 [USACO05DEC] Layout G 排队布局

D118 最短路→差分约束 SPFA 算法 P4878 [USACO05DEC] Layout G 排队布局_哔哩哔哩_bilibili

 

P4878 [USACO05DEC] Layout G - 洛谷

给 n 个点,m1+m2 个约束条件,求最大解。

思路

不等式的约束条件:

1. 相邻编号的牛之间的距离大于等于 0,即 $i-(i-1)\ge 0$

2. 基友 $a,b$ 之间的距离小于等于 $c$,即 $b-a\le c$

3. 情敌 $a,b$ 之间的距离大于等于 $c$,即 $b-a\ge c$

因为求最大解,把约束条件均转化为 $\le$,建图,跑最短路,判负环

判负环时,把所有点入队,以免走不到负环。不存在负环时,从 1 号点开始搜索,答案在 d[n]

image

相关板子:

D116【模板】最短路→差分约束 SPFA 算法 P5960 差分约束 - 董晓 - 博客园

 

// 差分约束 SPFA 算法 O(NM)
#include<bits/stdc++.h>
using namespace std;

const int N=1005,M=21005;
int h[N],to[M],ww[M],ne[M],idx;
void add(int a,int b,int c){
  to[++idx]=b,ww[idx]=c,ne[idx]=h[a],h[a]=idx;
}
int n,m1,m2;
int d[N],cnt[N];
bool vis[N];

bool spfa(int siz){
  memset(d,0x3f,sizeof d);
  memset(vis,0,sizeof vis);
  memset(cnt,0,sizeof cnt);
  queue<int> q;
  for(int i=1;i<=siz;i++)d[i]=0,q.push(i),vis[i]=true;
  
  while(!q.empty()){
    int u=q.front();q.pop();vis[u]=false;
    for(int i=h[u]; i; i=ne[i]){
      int v=to[i];
      if(d[v]>d[u]+ww[i]){
        d[v]=d[u]+ww[i]; //最短路
        cnt[v]=cnt[u]+1; //走过的边数
        if(cnt[v]>=n) return true; //有负环
        if(!vis[v]) q.push(v),vis[v]=true;
      }
    }
  }
  return false;
}
int main(){
  scanf("%d%d%d",&n,&m1,&m2);
  for(int i=1; i<=n; i++){
    add(i,i-1,0); //(i-1)-i<=0
  }
  for(int a,b,c;m1--;){
    scanf("%d%d%d",&a,&b,&c);
    add(a,b,c); //b-a<=c
  }
  for(int a,b,c;m2--;){
    scanf("%d%d%d",&a,&b,&c);
    add(b,a,-c); //a-b<=-c
  }
  
  if(spfa(n)) puts("-1"); //有负环则无解
  else{
    spfa(1);
    if(d[n]==0x3f3f3f3f) puts("-2"); //无穷大
    else printf("%d\n",d[n]);
  }
}

 

posted @ 2026-03-30 19:31  董晓  阅读(84)  评论(0)    收藏  举报