1. 程式人生 > >Cashier Employment 差分約束

Cashier Employment 差分約束

front 現在 isp 不知道 要求 size clr its 的人

  

題意:有一個超市需要一些出納員,已給出這個超市在各個時間段(0-1,1-2,2-3...共24個時間段)至少需要的出納員數目,
現在前來應聘有n個人,每個人都有一個固定的開始工作的時間,這也意味著從這個時間開始他要連續工作8個小時。在滿足這
個超市對出納員的需求的前提下,讓你求出最少雇傭的出納員人數。

need[i]表示在第 i 個小時至少也要的人數,work[i]表示應聘者中可以在第i個小時開始工作的人數,s[i]表示前i個小時雇傭的人數,

x[ i ]表示第 i 個小時雇傭的人數。 s[i] - s[i - 1] = x[i]

約束條件:
(1) 0<= x[i] <= x[ i ] ,轉化為 0 <= s[ i ] - s[i - 1] <= work[ i ]

(2) i >= 8 時:need[ i ] <= x[i] + x[i - 1] + x[i - 2] + x[i - 3] + x[i - 4] + x[i - 5] + x[i - 6] + x[i - 7]
轉化為 need[ i ] <= s[ i ] - s[i - 8]
i < 8 時:s[ i ] +s[ 24 ] -s[16 + i] >= need[i] (不清楚的可以模擬一下)
(3)對上面的S[24]我們不知道它的值,但我們知道它表示前24個小時所雇用的總人數,也就是我們要求的結果sum.因此對於未知
的sum,我們需要從0到n枚舉sum。需要再建一條邊即:s[24] - s[0] >= sum

二分人數即可

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define
RS(s) scanf("%s",s); #define ll long long #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f #define N 100000 int head[N]; int pos; struct node { int to,v,nex; }edge[N<<2]; void add(int a,int b,int c) { edge[++pos].nex=head[a]; head[a]=pos; edge[pos].v=c; edge[pos].to=b; } int n; int vis[N],dis[N],cnt[N]; int work[N],need[N]; void getmap(int k) { rep(i,1,24) { add(i-1,i,0); add(i,i-1,-work[i]); if(i>=8) add(i-8,i,need[i]); else add(16+i,i,need[i]-k); } add(0,24,k); } bool spfa(int k) { rep(i,1,24) vis[i]=0,dis[i]=-inf,cnt[i]=0; dis[0]=0; vis[0]=1; cnt[0]++; queue<int>q; q.push(0); while(!q.empty()) { int u=q.front();q.pop(); vis[u]=0; for(int i=head[u];i;i=edge[i].nex) { int v=edge[i].to; if(dis[v]<dis[u]+edge[i].v) { dis[v]=dis[u]+edge[i].v; if(!vis[v]) { if(++cnt[v]>24)return 0; vis[v]=1; q.push(v); } } } } return dis[24]==k; } int main() { int cas; RI(cas); while(cas--) { rep(i,1,24) RI(need[i]); CLR(work,0); int k;RI(k); rep(i,1,k) { int x;RI(x);work[x+1]++; } int L=0,R=k; int ans=-1; while(L<=R) { int mid=(L+R)>>1; pos=0;CLR(head,0); getmap(mid); if(!spfa(mid))L=mid+1; else R=mid-1,ans=mid; } if(ans!=-1) cout<<ans<<endl; else printf("No Solution\n"); } }
View Code

Cashier Employment 差分約束