其实我个人的看法,觉得差分约束最难的还是要把问题的限制想全,如果遗漏了一个点肯定错,然后求最大值就是<=k1,k2,k3,因为都要满足所以肯定要求k里面的最小值,最短路,求最小值>=k1,k2,k3,就是求最大值,最长路。最短路对应负环,最长路对应正环,如果传统队列的spfa太慢那就考虑把队列换成栈,不过一般情况下不要乱用,在更新值的方面,队列比栈要快不少。

模板题,看清楚题目问的最值是最小还是最大,该题是最小那么我们求最长路,最长路对应的是>=,即a>=b+w,a,b分别为端点,w为边权,如果存在正环就输出无解。

#include<iostream>
#include<cstring>
using namespace std;
const int N=100010,M=N*3;
int h[N],q[N],w[M],idx,e[M],ne[M];
int dist[N];
bool st[N];
int cnt[N];
int n,k;
void add(int a,int b,int c)
{
   
  e[idx] =b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int spfa()
{
   
  int tt=0,hh=0;
  memset(dist,-0x3f,sizeof dist);
  dist[0]= 0;
  q[tt++]=0;
  st[0]=true;
  while(tt!=hh)
  {
   
    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 -1;
        if(!st[j])
        {
   
          st[j] = true;
          q[tt++]=j;
        }
      }
    }
  }
  return 1;
}
int main()
{
   
  scanf("%d%d",&n,&k);
  memset(h,-1,sizeof h);
  while(k--)
  {
   
    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);
  int t=spfa();
  if(t==-1)
  cout<<-1<<endl;
  else
  {
   
    long long res=0;
    for(int i=1;i<=n;i++)
    res +=dist[i];
    cout<<res<<endl;
  }
  
  return 0;
}

题2:区间

解题思路:这题我们把所有dist看成前缀和,然后就很好办了,最后答案是所有区域内的答案。

#include<iostream>
#include<cstring>
using namespace std;
const   int N=50010,M=4*N;
int q[N],h[N],idx,e[M],ne[M],w[M];
bool st[N];
int dist[N];
int cnt[N];
int n;
void add(int a,int b,int c)
{
   
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void spfa()
{
   
  int tt=0,hh=0;
  memset(dist,-0x3f,sizeof dist);
  dist[0]=0;
  st[0]=true;
  q[tt++]=0;
  while(tt!=hh)
  {
   
    int t=q[hh++];
    st[t]=false;
    if(hh==N) hh=0;
    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];
        if(!st[j])
        {
   
          st[j]=true;
          q[tt++]=j;
          if(tt==N) tt=0;
        }
      }
    }
  }
}
int main()
{
   
    cin >> n;
    memset(h,-1,sizeof h);
    for(int i=0;i<n;i++)
    {
   
        int a,b,c;
        cin >>a>>b>>c;
        add(a-1,b,c);
    }
    for(int i=1;i<=50001;i++)
    add(i-1,i,0);
    for(int i=1;i<=50001;i++)
    add(i,i-1,-1);
    spfa();
    cout<<dist[50001]<<endl;
}

题3:1170. 排队布局

解题思路:这题我们把求的是最短路,如果有负环就输出-1,我们dist记录的是每头牛到万能源点0的距离,由于是求的是相对差,我们不妨把dist1变为0,先spfa一遍从万能源点0开始看看有没有负环,然后再spfa从1开始如果dist最后是0x3f3f3f3f那么就是无限长,否则输出distn就行了。

#include<iostream>
#include<cstring>
using namespace std;
const   int N =1010 , M = 30010;
bool st[N];
int dist[N];
int  q[N];
int h[N],idx,e[M],ne[M],w[M];
int cnt[N];
int n;
int ml,md;
void add(int a,int b,int c)
{
   
    e[idx] =b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa(int size)
{
   
  memset(st,0,sizeof st);
  memset(cnt,0,sizeof cnt);
  memset(dist,0x3f,sizeof dist);
  int tt=0,hh=0;
  for(int i=1;i<=size;i++)
  q[tt++] = i,st[i]=true;
  dist[1] = 0;
  while(hh!=tt)
  {
   
    int t=q[hh++];
    if(hh==N)   hh=0;
    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 true;
        if(!st[j])
        {
   
          st[j]=true;
          q[tt++]=j;
          if(tt==N) tt=0;
        }
      }
    }
  }
  return false;
}
int main()
{
    
    cin >> n >> ml >> md;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++)
    add(i,i-1,0);
    while(ml--)
    {
   
      int a,b;
      int D;
      cin >> a >> b >> D;
      if(b<a)
      swap(a,b);
      add(a,b,D);
    }
    while(md--)
    {
   
      int a,b;
      int D;
      cin >> a >> b >> D;
      if(b<a)
      swap(a,b);  
      add(b,a,-D);    
    }
    if(spfa(n))
    cout<<-1<<endl;
    else
    {
   
      spfa(1);
      if(dist[n]==0x3f3f3f3f)
      cout<<-2<<endl;
      else
      {
   
        cout<<dist[n]<<endl;
      }
      
    }
      return 0;
} 

题目4:393. 雇佣收银员

解题报告:这题的dist代表前i个小时总共雇了多少个员工,由于不知道dist24,那么我们可以枚举他的大小,从0到总人数,只需要看i执行到什么时候最长路不存在正环就输出i。

#include<iostream>
#include<cstring>
using namespace std;
const int N =24 ,  M =100;
int h[N],idx , ne[M],e[M],w[M];
int  dist[N];
int num[N];
bool st[N];
int r[N];
int T;
int q[N];
int cnt[N];
void add(int a,int b,int c)
{
   
  e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void build(int size)
{
   
  for(int i=1;i<=24;i++)
  {
   
    add(i-1,i,0);
    add(i,i-1,-num[i]);
    if(i<8)
    add(i+16,i,r[i]-size);
    else
    {
   
      add(i-8,i,r[i]);
    }
    
  }

}
bool spfa(int size)
{
   
    memset(cnt,0,sizeof cnt);
    memset(st,0,sizeof st);
    memset(dist,-0x3f,sizeof dist);
    memset(h,-1,sizeof h);
    idx = 0 ;
    build(size);
    int hh =0 ,tt=0;
    q[tt++]=0;
    dist[0] =0;
    while(tt!=hh)
    {
   
      int t = q[hh++];
      st[t]=false;
      if(hh==N) hh=0;
      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]>=25)  return false;//0也算在其中
          if(!st[j])
          {
   
              st[j] =true;
              q[tt++]=j;
              if(tt==N)  tt=0;

          }
        }
      }
    }
    return true;
}
int main()
{
   
    int t;
  cin >> t;
  while(t--)
  {
   
    memset(num,0,sizeof num);
    for(int i=1;i<=24;i++)
    cin >> r[i];
    int n;
    cin >> n;
    for(int i=0;i<n;i++)
    {
   
          int x;
           cin >> x;
           num[x+1]++;
    }
    bool flag=0;
    for(int i =0;i<=1000;i++)
    {
   
        if(spfa(i))
        {
   
            flag =true; 
            cout<<i<<endl;
            break;
        }
    } 
    if(!flag)
    cout<<"No Solution"<<endl;
  }
  return 0;
}