POJ1275 Cashier Employment 二分 + 差分约束
Posted mychael
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1275 Cashier Employment 二分 + 差分约束相关的知识,希望对你有一定的参考价值。
题目链接
题解
显然可以差分约束
我们记(W[i])为(i)时刻可以开始工作的人数
令(s[i])为前(i)个时刻开始工作的人数的前缀和
每个时刻的要求(r[i]),可以通过如下限制满足:
[s[i] - s[i - 8] ge r[i]]
[0 le s[i] - s[i - 1] le W[i]]
但是(i - 8)可能为负,回到上一天的时刻,导致区间不连续,不好处理
我们可以二分答案(sum)
将(i < 8)的部分改为:
[s[i + 16] - s[i] le sum - R[i]]
再加一个
[s[24] - s[0] ge sum]
这样就可以了
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 105,maxm = 1000005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
}
int n,R[50],W[50];
int d[maxn],vis[maxn],cnt[maxn];
int q[maxm],head,tail;
bool spfa(){
for (int i = 0; i <= 24; i++) d[i] = -INF,vis[i] = false,cnt[i] = 0;
d[0] = 0; q[head = tail = 0] = 0;
int u;
while (head <= tail){
u = q[head++];
vis[u] = false; cnt[u]++;
if (cnt[u] >= 25) return false;
Redge(u) if (d[to = ed[k].to] < d[u] + ed[k].w){
d[to] = d[u] + ed[k].w;
if (!vis[to]) vis[to] = true,q[++tail] = to;
}
}
return true;
}
bool check(int sum){
for (int i = 1; i <= 24; i++) if (R[i] > sum) return false;
cls(h); ne = 0;
for (int i = 1; i < 8; i++) build(i + 16,i,R[i] - sum);
for (int i = 8; i <= 24; i++) build(i - 8,i,R[i]);
for (int i = 1; i <= 24; i++){
build(i - 1,i,0);
build(i,i - 1,-W[i]);
}
build(0,24,sum);
return spfa();
}
int main(){
int T = read();
while (T--){
for (int i = 1; i <= 24; i++)
R[i] = read(),W[i] = 0;
n = read(); int x;
REP(i,n){
x = read() + 1;
W[x]++;
}
int l = 0,r = n,mid,flag = false;
while (l < r){
mid = l + r >> 1;
if (check(mid)) r = mid,flag = true;
else l = mid + 1;
}
if (!flag) puts("No Solution");
else printf("%d
",l);
}
return 0;
}
以上是关于POJ1275 Cashier Employment 二分 + 差分约束的主要内容,如果未能解决你的问题,请参考以下文章
图论(差分约束系统):POJ 1275 Cashier Employment
poj 1275 Cashier Employment - 差分约束 - 二分答案
POJ1275 Cashier Employment[差分约束系统 || 单纯形法]