設num[i] 為來應聘的在第i個小時開始工作的人數
r[i] 為第i個小時至少需要的人數
x[i] 為招到的在第i個小時開始工作的人數
根據題意有:
0 <= x[i] <= num[i]
x[i] + x[i-1] + …+ x[i-7] >= r[i] (題目中的連續工作8小時)
再設 s[i] = x[1] + … + x[i]
則有: s[i] – s[i-1] >= 0
s[i-1] – s[i] >= –num[i]
s[i] – s[i-8] >= r[i], 8 <= i <= 24
s[i] – s[i+16] >= r[i] – s[24], 1<= i <= 7
還需要添加一個隱藏不等式: s[24] – s[0] >= ans(枚舉的答案)
通過枚舉s[24],來檢測是否滿足條件,題目是求最小值,即求最長路,以0為源點。
CODE:
/*差分約束*//*AC代碼15ms*/#include <iostream>#define MAXN 1005#define INF 0x7fffffffstruct edge{int to,w,next; }E[4*MAXN];int head[MAXN],ecnt;int Stack[MAXN],cnt[MAXN],dis[MAXN],R[25],X[25],t[25];bool Instack[MAXN];int N,top;void Insert(int from,int to,int w){E[ecnt].to=to;E[ecnt].w=w;E[ecnt].next=head[from];head[from]=ecnt++; }void Init(){int i,u;for(i=1;i<=24;i++){scanf("%d",&R[i]);t[i]=0; }scanf("%d",&N);for(i=1;i<=N;i++){scanf("%d",&u);t[u+1]++;}}void Build_Map(int mid){int i;memset(head,-1,sizeof(head));ecnt=0;// 0<=x[i]-x[i-1]<=t[i]for(i=1;i<=24;i++){Insert(i,i-1,-t[i]);Insert(i-1,i,0); }//x[24]+x[i]-x[i-8+24]>=r[i]for(i=1;i<=8;i++)Insert(i-8+24,i,-mid+R[i]);//x[i]-x[i-8]>=r[i]for(i=9;i<=24;i++)Insert(i-8,i,R[i]);//x[24]-x[0]>=x[24]。注意Insert(0,24,mid);}bool SPFA(int mid){int i,u,v,w;memset(cnt,0,sizeof(cnt));memset(Instack,false,sizeof(Instack));for(i=0;i<=24;i++)//注意這裡是到24dis[i]=-INF;top=0;Stack[top++]=0;dis[0]=0;cnt[0]=1;//注意Instack[0]=true;while(top){u=Stack[--top];Instack[u]=false;cnt[u]++;if(cnt[u]>N)return false;for(i=head[u];i!=-1;i=E[i].next){v=E[i].to;w=E[i].w;if(dis[v]<dis[u]+w){dis[v]=dis[u]+w;if(!Instack[v]){Stack[top++]=v;Instack[v]=true;}}}}return dis[24]==mid;}int main(){int T;scanf("%d",&T);while(T--){Init();int l=0,r=N+1;while(r>l)//二分X[24]{int mid=(l+r)>>1;Build_Map(mid);//構圖if(SPFA(mid))r=mid;else l=mid+1; }if(r==N+1)printf("No Solution\n");elseprintf("%d\n",r); }return 0;}