题目大意:
德黑兰的一家每天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)更多的出纳员在工作
输入描述:
输入文件的第1行为一个整数T,表示输入文件中测试数据的数目(至多20个)。每个测试数据第一行为24个整数,表示R(0),R(1),...,R(23),R(i)最大可以取到1000。接下来一行是一个整数N,表示申请者的数目,0<=N<=1000。接下来有N行,每行为一个整数ti,0<=ti<=23,测试数据之间没有空行。
输出描述:
对输入文件中的每个测试数据,输出占一行,为需要雇佣的出纳员的最少数目。如果某个测试数据没有解。则输出"No Solution"。
分析:这道题很难啊,变态夏令营老师竟然把这当作业,做完之后感觉对差分约束系统又有更深一步的了解。
差分约束系统的关键就是要找不等式,然后化成一种形式,跑最长路/最短路,关键就是这个不等式要怎么找,黑书上有详细的解释:
其实也用不到二分法,直接枚举就好了,我们spfa求出来的d[24]其实是s[24] - s[0],因为我们人为规定s[0] = 0,所以d[24]也就是答案了。
到目前为止遇到了两类差分约束系统的问题,一类是告诉你sum,问你有没有解,第二种是告诉你条件,求解,第二种枚举解就好了,第一种就是判环.
坑的是我最长路写错了,有存在边权为0的情况,所以d数组每次都要初始化为-1.
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<map> using namespace std; const int inf = 0x7ffffff; int T,t[30],r[30],ans,n,head[110],to[110],nextt[110],w[110],tot,d[110],vis[110],cnt[110]; void add(int x, int y, int z) { w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void build(int sum) { memset(head, -1, sizeof(head)); tot = 0; add(0, 24, sum); for (int i = 1; i <= 24; i++) { add(i - 1, i, 0); add(i, i - 1, -t[i]); } for (int i = 1; i <= 8; ++i) add(i + 16, i, r[i] - sum); for (int i = 9; i <= 24; ++i) add(i - 8, i, r[i]); } bool spfa(int sum) { memset(vis, 0, sizeof(vis)); memset(cnt, 0, sizeof(cnt)); memset(d, -1, sizeof(d)); queue <int>q; vis[0] = 1; q.push(0); d[0] = 0; while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int i = head[u]; i + 1; i = nextt[i]) { int v = to[i]; if (d[v] < d[u] + w[i]) { d[v] = d[u] + w[i]; if (!vis[v]) { ++cnt[v]; if (cnt[v] > 24) return false; vis[v] = 1; q.push(v); } } } } if (d[24] == sum) return true; return false; } int main() { scanf("%d", &T); while (T--) { bool flag = false; memset(t, 0, sizeof(t)); for (int i = 1; i <= 24; i++) scanf("%d", &r[i]); scanf("%d", &n); for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); t[x + 1]++; } for (int i = 0; i <= n; ++i) { build(i); if (spfa(i)) { flag = true; printf("%d ", i); break; } } if (!flag) { printf("No Solution "); } } return 0; }