poj1275(差分约束)
POJ1275出纳员的雇佣【差分约束】
出纳员的雇佣
Tehran的一家每天24小时营业的超市,需要一批出纳员来满足它的需要。超市经理雇佣你来帮他解决问题:超市在每天的不同时段需要不同数目的出纳员(例如:午夜时只需一小批,而下午则需要很多)来为顾客提供优质服务。他希望雇佣最少数目的出纳员。
经理已经提供你一天的每一小时需要出纳员的最少数量——R(0),
R(1), ...,
R(23)。R(0)表示从午夜到上午1:00需要出纳员的最少数目,R(1)表示上午1:00到2:00之间需要的,等等。每一天,这些数据都是相同的。有N人申请这项工作,每个申请者I在24小时中,从一个特定的时刻开始连续工作恰好8小时,定义tI
(0 <= tI <= 23)为上面提到的开始时刻。也就是说,如果第I个申请者被录取,他(她)将从tI 时刻开始连续工作8小时。
你将编写一个程序,输入R(I)(I = 0..23)和tI (I = 1..N),它们都是非负整数,计算为满足上述限制需要雇佣的最少出纳员数目。在每一时刻可以有比对应的R(I)更多的出纳员在工作。
输入格式:
输入文件的第一行为测试点个数(<= 20)。每组测试数据的第一行为24个整数表示R(0),R(1),..., R(23)(R(I)<= 1000)。接下来一行是N,表示申请者数目(0 <= N <= 1000),接下来每行包含一个整数tI (0 <= tI <= 23)。两组测试数据之间没有空行。输出格式:
对于每个测试点,输出只有一行,包含一个整数,表示需要出纳员的最少数目。如果无解,你应当输出“No Solution!”样例输入:
1
1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
5
0
23
22
1
10
样例输出:
1
时间限制:
1s(先每个时间段加一以便C++操作)
差分约束:
0 <= S[i]-S[i-1]<=W[i]; // 雇佣的人数少于申请者但不能为负数
S[i]-S[i-8]>=R[i] // 当i>=8时,该方程成立,否则将出现负数显然不成立
S[i+16]-S[i]<=x-R[i] // 当i<8时,由于昨天的雇人可以通宵上班,因此这个约束通过反面处理
S[24] - S[0] >=x // 最后24小时内雇佣人应该大于等于x个人
S[i]-S[i-8]>=R[i] // 当i>=8时,该方程成立,否则将出现负数显然不成立
S[i+16]-S[i]<=x-R[i] // 当i<8时,由于昨天的雇人可以通宵上班,因此这个约束通过反面处理
S[24] - S[0] >=x // 最后24小时内雇佣人应该大于等于x个人
S[i]-S[j]<=K 则从顶点j向i引一条权值为K的边。该系统是否成立也就在于是否存在负环,于是用SPFA判断负环。
然而x(也就是答案)未知,而x<=1000,所以可以二分查找找出最小的x。注意归零。
要讲一下的就是这个s[i+16]-s[i]<=x-R[i]
因为,我们的s[i]是表示1……i的人数和,那么要搞出s[i]-(昨天的)s[i-8],,,即s[i]-s[i+16],,但s[i]是第二天的
所以s[i]+x-s[i+16]>=R[i]
变形一下就成了s[i+16]-s[i]<=x-R[i]
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxn=30; int tu[maxn][maxn],cnt[maxn],go[maxn][maxn],vis[maxn],dis[maxn]; int n,m,r[maxn],s[maxn]; queue<int>Q; bool spfa(int x){ memset(tu,0,sizeof(tu)); memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(vis)); memset(cnt,0,sizeof(cnt)); vis[24]=1; cnt[24]=1; dis[24]=0; Q.push(24); for (int i=1;i<=24;i++) tu[i-1][i]=s[i]; for (int i=8;i<=24;i++) tu[i][i-8]=-r[i]; for (int i=1;i<=7;i++) tu[i][i+16]=x-r[i]; tu[24][0]=-x; while(!Q.empty()){ int u=Q.front(); Q.pop(); vis[u]=false; for (int i=0;i<=24;i++){ if(go[u][i]&&dis[i]>dis[u]+tu[u][i]){ dis[i]=dis[u]+tu[u][i]; if(!vis[i]){ Q.push(i); cnt[i]++; vis[i]=true; if(cnt[i]>25) return false; } } } } return true; } int main(){ int t; scanf("%d",&t); for (int i=1;i<=24;i++) go[i][i-1]=go[i-1][i]=true; for (int i=8;i<=24;i++) go[i][i-8]=true; for (int i=1;i<=7;i++) go[i][i+16]=true; go[24][0]=true; while(t--){ memset(s,0,sizeof(s)); int n; int x; for (int i=1;i<=24;i++) scanf("%d",&r[i]); scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&x); s[x+1]++; } int l=1; int r=n; bool falg=false; int mid; while(l<=r){ mid=(l+r)/2; if(spfa(mid)) { r=mid-1; falg=true; } else l=mid+1; } if(falg) printf("%d\n",l); else printf("No Solution\n"); } return 0; }