题意:给出一个超市一天24小时每个小时需要的人手,再给出n个应聘者的上班时间,每个人每次上班连续8个小时,问最少要聘请多少人。
分析:c[i]表示第i小时需要的人手,t[i]表示第i小时开工的人数,s[i]表示最终聘请的人里面在[0,i]之间开始工作的人的总数。转化为不等式组:s[i+1]-s[i]>=0(i+1小时开始上班的人数最少是0),s[i+1]-s[i]<=t[i+1](i+1小时开始上班的人数最多为t[i+1]),j+8=i && s[i]-s[j]>=c[i],i=(j+8)%24 && s[i]-s[j]>=c[i]-mid(满足i小时的人手需求,mid是最终聘请人数可能的范围[left,right]的中值,要用二分法查找满足条件的最小答案),s[24]-s[0]>=mid(其实是等于)。
#include<cstdio> #include<queue> using namespace std; struct weighed_arc { int v,weight,next; }; weighed_arc arc[100000]; queue<int> que; int t[25],c[25],caseNum,n,m,sum,first[25],visited[25]; bool inque[25]; bool spfa(int s) { int dis[25]; dis[0]=0; for(int i=0;i<25;i++) { visited[i]=0; dis[i]=-0xfffff; inque[i]=false; } dis[0]=0; visited[0]=1; que.push(0); inque[0]=true; while(!que.empty()) { int u=que.front(); que.pop(); inque[u]=false; for(int i=first[u];i!=-1;i=arc[i].next) { int v=arc[i].v; if(dis[v]<dis[u]+arc[i].weight) { dis[v]=dis[u]+arc[i].weight; if(!inque[v]) { que.push(v); inque[v]=true; visited[v]++; if(visited[v]>=25) return false; } } } } return true; } int main() { scanf("%d",&caseNum); while(caseNum--) { for(int i=1;i<=24;i++) scanf("%d",&c[i]); scanf("%d",&n); for(int i=0;i<=24;i++) t[i]=0; sum=n; for(int i=0;i<n;i++) { int x; scanf("%d",&x); t[x+1]++; } bool flag=false; int left=0,right=2*sum,mid; while(left<right) { mid=(left+right)/2; for(int i=0;i<25;i++) first[i]=-1; //s[i+1]-s[i]>=0 for(int i=0;i<24;i++) { arc[i].v=i+1; arc[i].weight=0; arc[i].next=first[i]; first[i]=i; } m=24; //s[i+1]-s[i]<=t[i+1] ( s[i]-s[i+1]>=-t[i+1] ) for(int i=0;i<24;i++) { arc[m].v=i; arc[m].weight=-t[i+1]; arc[m].next=first[i+1]; first[i+1]=m++; } //s[24]-s[0]>=mid arc[m].v=24; arc[m].weight=mid; arc[m].next=first[0]; first[0]=m++; for(int j=0;j<24;) { int i=(j+8)%24; i++;j++; arc[m].v=i; if(i>j)//i>j && j+8=i , s[i]-s[j]>=c[i] arc[m].weight=c[i]; else//i<j && i=(j+8)%24 , s[i]-s[j]>=c[i]-mid arc[m].weight=c[i]-mid; arc[m].next=first[j]; first[j]=m++; } arc[m].v=8; arc[m].next=first[0]; first[0]=m; arc[m++].weight=c[8]; /* for(int i=0;i<25;i++) { printf("%d:",i); for(int j=first[i];j!=-1;j=arc[j].next) printf("%d,",arc[j].v); printf("\n"); } getchar()*/; if(spfa(0)) right=mid; else left=mid+1; } if(right<=n) printf("%d\n",right); else printf("No Solution\n"); } return 0; }