1 条题解

  • 0
    @ 2026-6-16 15:54:08

    // 差分约束 SPFA 算法 O(NM*logN)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=25,M=100;
    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;
    int r[N],num[N];
    int d[N],cnt[N],vis[N];
    
    void build(int mid){
      idx=0; memset(h,0,sizeof h);
      for(int i=1; i<=24; i++){
        add(i-1,i,0);
        add(i,i-1,-num[i]);
      }
      for(int i=8; i<=24; i++) add(i-8,i,r[i]);
      for(int i=1; i<=7; i++) add(i+16,i,r[i]-mid);
      add(0,24,mid); add(24,0,-mid);
    }
    bool spfa(int mid){
      build(mid); //建图
      memset(d,-0x3f,sizeof d); d[0]=0;
      memset(cnt,0,sizeof cnt);
      memset(vis,0,sizeof vis);
      queue<int> q; 
      q.push(0);vis[0]=true; //0就是超级源点
      
      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]>=25) return 1; //有正环
            if(!vis[v]) q.push(v),vis[v]=true;
          }
        }
      }
      return 0; //无正环
    }
    int main(){
      int T; cin>>T;
      while(T--){
        for(int i=1; i<=24; i++)cin>>r[i]; //每个时刻的需要人数
        cin>>n;
        memset(num,0,sizeof num);
        for(int i=1,t; i<=n; i++){
          cin>>t;
          num[t+1]++; //每个时刻的应聘人数
        }
        int l=-1,r=n+1;
        while(l+1<r){
          int mid=l+r>>1;
          if(!spfa(mid)) r=mid; //如果无正环,说明人多
          else l=mid;
        }
        if(r==n+1) cout<<"No Solution\n";
        else cout<<r<<"\n";
      }
    }
    
    • 1

    D119 差分约束[ICPC 2000 Tehran R] Cashier Employment雇佣收银员

    信息

    ID
    1482
    时间
    1000ms
    内存
    10MiB
    难度
    3
    标签
    递交数
    30
    已通过
    20
    上传者