2 条题解

  • 0
    @ 2025-10-8 16:59:09

    题解分析

    by hansang

    本题要求最小数目,因此采用最长路算法。

    变量说明:

    • r[i]: 要求有多少人在工作
    • x[i]: 实际有多少人开始工作
    • s[i]: x[i]的前缀和
    • c[i]: 最多可以有多少人在工作

    约束条件:

    • 0 <= x[i] <= c[i] => 0 <= s[i] - s[i-1] <= c[i]
      • 0 <= s[i] - s[i-1] => s[i-1] + 0 <= s[i] (1)[1, 24]
      • s[i] - s[i-1] <= c[i] => s[i] - c[i] <= s[i-1] (2)[1, 24]
    • 连续8天的工作人数和 >= r[i]:x[i-7] + x[i-6] + x[i-5] + x[i-4] + x[i-3] + x[i-2] + x[i-1] >= r[i] => s[i] - s[i-8] >= r[i] => s[i-8] + r[i] <= s[i] (3)[9, 24]
    • 连续17天的工作人数和 >= r[i]:x[i+17] + x[i+18] + x[i+19] + ... + x[24] + x[1] + x[2] + ... + x[i] >= r[i] => s[24] - s[i+16] + s[i] >= r[i] => s[i+16] + r[i] - s[24] <= s[i] (4)[1, 8]

    代码实现

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 30;
    int R[N], c[N], d[N], t[N];
    struct node { int x, d; };
    vector<node> G[N];
    queue<int> Q; bool v[N];
    
    int spfa() {
        memset(v, 0, sizeof(v));
        memset(t, 0, sizeof(t));
        memset(d, -0x3f, sizeof(d));
        Q.push(0); v[0] = 1; d[0] = 0;
        while (!Q.empty()) {
            int x = Q.front(); Q.pop(); v[x] = 0;
            for (node i : G[x]) {
                int y = i.x, w = i.d;
                if (d[y] < d[x] + w) {
                    d[y] = d[x] + w;
                    if (!v[y]) {
                        Q.push(y); v[y] = 1;
                        t[y]++; if (t[y] > 25) return 0;
                    }
                }
            }
        }
        return 1;
    }
    
    bool check(int x) {
        memset(G, 0, sizeof(G));
        for (int i = 1; i <= 24; i++) G[i-1].push_back({i, 0}); // (1)
        for (int i = 1; i <= 24; i++) G[i].push_back({i-1, -c[i]}); // (2)
        for (int i = 9; i <= 24; i++) G[i-8].push_back({i, R[i]}); // (3)
        for (int i = 1; i <= 8; i++) G[i+16].push_back({i, R[i] - x}); // (4)
        G[0].push_back({24, x}); G[24].push_back({0, -x}); // s[0] + x = s[24]
        return spfa();
    }
    
    int main() {
        int T; scanf("%d", &T);
        while (T--) {
            memset(c, 0, sizeof(c));
            for (int i = 1; i <= 24; i++) scanf("%d", &R[i]);
            int n; scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                int x; scanf("%d", &x);
                c[x+1]++;
            }
            int l = 0, r = n, p = -1;
            while (l <= r) {
                int mid = (l + r) / 2;
                if (check(mid)) r = mid - 1, p = mid;
                else l = mid + 1;
            }
            if (p == -1) printf("No Solution\n");
            else printf("%d\n", p);
        }
        return 0;
    }
    
    • 0
      @ 2025-10-8 16:58:51

      by hansang:

      /* by hansang
      求最小数目,所以跑最长路 
      r[i]:要求有多少人在工作
      x[i]:实际有多少人开始工作
      s[i]:x[i]的前缀和 
      c[i]:最多可以有多少人在工作 
       
      0<=x[i]<=c[i] => 0<=s[i]-s[i-1]<=c[i]
      0<=s[i]-s[i-1]      =>      s[i-1]+0<=s[i] (1)[1, 24]
      s[i]-s[i-1]<=c[i]     =>    s[i]-c[i]<=s[i-1] (2)[1, 24]
      
      x[i-7]+x[i-6]+x[i-5]+x[i-4]+x[i-3]+x[i-2]+x[i-1]+x[i-1]>=r[i]
      s[i]-s[i-8]>=r[i]     =>    s[i-8]+r[i]<=s[i] (3)[9, 24]
      
      x[i+17]+x[i+18]+x[i+19]+...+x[24]+x[1]+x[2]+...+x[i]>=r[i]
      s[24]-s[i+16]+s[i]>=r[i] => s[i+16]+r[i]-s[24]<=s[i] (4)[1, 8]
      */
      #include<bits/stdc++.h>
      using namespace std;
      const int N=30;
      int R[N], c[N], d[N], t[N];
      struct node{int x, d;};
      vector<node> G[N];
      queue<int> Q; bool v[N];
      int spfa(){
      	memset(v, 0, sizeof(v));
      	memset(t, 0, sizeof(t));
      	memset(d, -0x3f, sizeof(d));
      	Q.push(0); v[0]=1; d[0]=0;
      	while(!Q.empty()){
      		int x=Q.front(); Q.pop(); v[x]=0;
      		for(node i: G[x]){
      			int y=i.x, w=i.d;
      			if(d[y]<d[x]+w){
      				d[y]=d[x]+w;
      				if(!v[y]){
      					Q.push(y); v[y]=1;
      					t[y]++; if(t[y]>25) return 0;
      				}
      			}
      		}
      	}
      	return 1;
      }
      bool check(int x){
      	memset(G, 0, sizeof(G));
      	for(int i=1; i<=24; i++) G[i-1].push_back({i, 0}); //(1) 
      	for(int i=1; i<=24; i++) G[i].push_back({i-1, -c[i]}); //(2) 
      	for(int i=9; i<=24; i++) G[i-8].push_back({i, R[i]}); //(3) 
      	for(int i=1; i<=8; i++) G[i+16].push_back({i, R[i]-x}); //(4) 
      	G[0].push_back({24, x}); G[24].push_back({0, -x}); //s[0]+x=s[24]
      	return spfa();
      }
      int main(){
      	int T; scanf("%d", &T);
      	while(T--){
      		memset(c, 0, sizeof(c));
      		for(int i=1; i<=24; i++) scanf("%d", &R[i]);
      		int n; scanf("%d", &n);
      		for(int i=1; i<=n; i++){
      			int x; scanf("%d", &x);
      			c[x+1]++;
      		}
      		int l=0, r=n, p=-1;
      		while(l<=r){
      			int mid=(l+r)/2;
      			if(check(mid)) r=mid-1, p=mid;
      			else l=mid+1;
      		}
      		if(p==-1) printf("No Solution\n");
      		else printf("%d\n", p);
      	} 
      	return 0;
      }
      • 1

      *【差分约束】出纳员问题[POJ1275]

      信息

      ID
      1871
      时间
      1000ms
      内存
      512MiB
      难度
      9
      标签
      递交数
      13
      已通过
      3
      上传者