设num[i] 为在i时刻可以工作的应聘人数
x[i] 在i时刻招聘的人数
m[i] 在i时刻要求最少的工作人数
由题意建立起约束:
(1)0 <= x[i] <= num[i]
(2)x[i-7] + x[i-6 ]+.....+ x[i] >= m[i] (因为工作8小时) (i<7时要特殊考虑)
设s[i] = x[1] + x[2] + .....+ x[i] 从第0时刻到第i时刻招聘的总人数
将约束转化为 差分形式:
由(1):
s[i] - s[i-1] >= 0 1 <= i <= 24 ( 第i时刻可能不招人)
s[i-1] - s[i] >= -num[i] 1 <= i <= 24
由(2):
s[i] - s[i-8] >= m[i] 9 <= i <= 24 (不受一天的影响)
s[i] - s[i+16] >= m[i] - s[24] 1 <= i <= 8 (受上一天的影响)
特加条件: s[24] - s[0] >= ans
不妨假设s[24]为ans,以0点为源点跑最长路有解,且s[24]=ans。说明此解有效。
所以最长路作为二分搜索的判断条件。搜索可行解。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <vector> #include <queue> #define MAX_N 25 #define INF 0x7fffffff using namespace std; struct edge{ int to,val; }; bool inque[MAX_N]; int dist[MAX_N]; int vis[MAX_N]; int s[MAX_N]; int num[MAX_N]; int m[MAX_N]; vector<edge> g[MAX_N]; int init() { for(int i=0;i<MAX_N;++i) g[i].clear(); } void add_edge(int u,int v,int val) { g[u].push_back((edge){v,val}); } void bulidGraph(int ans) { // s[i] – s[i-1] >= 0 // s[i-1] – s[i] >= –num[i] // s[i] – s[i-8] >= r[i], 9 <= i <= 24 // s[i] – s[i+16] >= r[i] – s[24], 1<= i <= 8 // s[24] – s[0] >= ans for(int i=1;i<=24;++i) add_edge(i-1,i,0); for(int i=1;i<=24;++i) add_edge(i,i-1,-num[i]); for(int i=9;i<=24;++i) add_edge(i-8,i,m[i]); for(int i=1;i<=8;++i) add_edge(i+16,i,m[i]-ans); add_edge(0,24,ans); } bool spfa(int start,int res) { queue<int> que; for(int i=0;i<MAX_N;++i) dist[i]=-INF; memset(inque,0,sizeof(inque)); memset(vis,0,sizeof(vis)); dist[start]=0; que.push(start); inque[start]=1; while(!que.empty()) { int u=que.front();que.pop(); inque[u]=0; ++vis[u]; if(vis[u]>MAX_N) return false; for(int i=0;i<g[u].size();++i) { edge &e=g[u][i]; if(dist[e.to]<dist[u]+e.val) { dist[e.to]=dist[u]+e.val; if(!inque[e.to]) { que.push(e.to); inque[e.to]=1; } } } } if(dist[24]==res) { return true; } return false; } int solve(int rb) { int lb=0; rb*=2; while(rb-lb>=1){ int mid=(rb+lb)/2; init(); bulidGraph(mid); if(spfa(0,mid)) rb=mid; else lb=mid+1; } return rb; } int main() { int t; scanf("%d",&t); while(t--) { for(int i=1;i<=24;++i) scanf("%d",&m[i]); int n; memset(num,0,sizeof(n)); scanf("%d",&n); int u,rb=0; for(int i=0;i<n;++i) { scanf("%d",&u); ++rb;++num[u+1]; } int ans=solve(rb); if(ans<=rb) printf("%d\n",ans); else printf("No Solution\n"); } return 0; }