2 条题解

  • 0
    @ 2026-6-16 16:39:30

    // 差分约束 SPFA 算法 O(NM)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=50005,M=N*3;
    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,d[N];
    bool vis[N];
    
    void spfa(){
      memset(d,-0x3f,sizeof d); d[0]=0;
      queue<int> q; q.push(0); vis[0]=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];
            if(!vis[v]) q.push(v),vis[v]=true;
          }
        }
      }
    }
    int main(){
    
        scanf("%d",&n);
        idx=0; memset(h,0,sizeof h);
        for(int i=1; i<N; i++){
          add(i-1,i,0);  //i-(i-1)>=0
          add(i,i-1,-1); //(i-1)-i>=-1
        }
        for(int i=1,a,b,c; i<=n; i++){
          scanf("%d%d%d",&a,&b,&c);
          a++,b++;
          add(a-1,b,c); //b-(a-1)>=c
        }
        
        spfa();
        printf("%d\n",d[50001]);
    
    }
    
    • 0
      @ 2025-10-8 16:57:16

      求最少点,所以求最长路,建边形式要求:

      xbxacx_b - x_a \ge c \to
      xa+cxbx_a + c \le x_b \to G[a].push_back({b,c})

      #include <bits/stdc++.h>
      using namespace std;
      const int N=5e4+10;
      vector<pair<int,int>>G[N]; 
      int n,d[N]; bool v[N];
      int spfa()
      { 
          memset(d,-0x3f,sizeof(d));
          memset(v,0,sizeof(v)); // 初始距离为负无穷,标记数组初始为未访问
          queue<int>q;q.push(0);d[0]=0;v[0]=1; // 起点0,距离0,标记为访问
          while(!q.empty())
          {
              int x=q.front();q.pop();v[x]=0; // 出队,标记为未访问
              for(auto i:G[x]) // 遍历x的邻接边
              {
                  int y=i.first, c=i.second; // 终点y,边权c
                  if(d[y]<d[x]+c) // 如果y的距离可以被更新
                  {
                      d[y]=d[x]+c; // 更新距离
                      if(!v[y]) q.push(y),v[y]=1; // 若未访问,入队并标记
                  }
              }
          }
          return d[n]; // 返回终点n的距离
      }
      int main()
      {
          int m; scanf("%d", &m); // 读入边数m 
          for(int i=1,x,y,c;i<=m;i++) // 读入m条边
          {
              scanf("%d%d%d",&x,&y,&c);
              x++;y++; // 点编号+1(可能原输入从1开始)
              G[x-1].push_back({y, c}); // 从x-1到y连边,权值c(满足xa+c <= xb)
             
          }
          n=50001; // 总点数n=50001
          for(int i=0;i<n;i++) // 添加点之间顺序约束的边
          {
              G[i+1].push_back({i,-1}); // 从i+1到i连边,权值-1(d[i+1] <= d[i]+1)
              G[i].push_back({i+1, 0}); // 从i到i+1连边,权值0(d[i] <= d[i+1])
          }
          printf("%d\n",spfa()); // 输出结果
          return 0;
      }
      
      • 1

      D117【差分约束】区间[ SPOJ116]Intervals

      信息

      ID
      1449
      时间
      1000ms
      内存
      128MiB
      难度
      7
      标签
      递交数
      167
      已通过
      38
      上传者