题目大意:
从0点到23点,给出每个时刻需要的售货员个数,再给出每个时刻应征的售货员个数,然后让你求出满足需求的最小售货员个数
解题思路:
差分约束
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
const int maxn = 1000;
typedef struct node{
int to, w;
int next;
}Edge;
int tot;
Edge edge[maxn];
int r[25], t[25];
int head[maxn], dis[30], vis[30], cnt[30];
void add(int u, int v, int w){
edge[tot].w = w;
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int spfa(int ans){
int p, v;
queue<int> q;
while(!q.empty()) q.pop();
for(int i = 0; i <= 24; ++i){
dis[i] = 0;
vis[i] = 1;
cnt[i] = 0;
q.push(i);
}
while(!q.empty()){
p = q.front(); q.pop(); vis[p] = 0;
if(++cnt[p] > 25) return 0;
for(int i = head[p]; ~i; i = edge[i].next){
v = edge[i].to;
if(dis[v] > dis[p] + edge[i].w){
dis[v] = dis[p] + edge[i].w;
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
if(-dis[24] == ans) return 1;
else return 0;
}
int solve(int ans){
tot = 0;
memset(head, -1, sizeof(head));
for(int i = 0; i < 24; ++i){
add(i, i+1, 0);
add(i+1, i, t[i+1]);
}
for(int j = 1; j <= 24; ++j){
if(j + 8 <= 24) add(j, j + 8, -r[j+8]);
else add(j, j-16, ans - r[j-16]);
}
add(0, 24, -ans);
if(spfa(ans)) return 1;
else return 0;
}
int main(){
int tt, n, a;
scanf("%d", &tt);
while(tt--){
for(int i = 1; i <= 24; ++i){
scanf("%d", &r[i]); t[i] = 0;
}
scanf("%d", &n);
for(int i = 0; i < n; ++i){
scanf("%d", &a); ++t[a+1];
}
int flag = 0;
for(int i = 0; !flag && i <= n; ++i){
flag = solve(i);
if(flag) {printf("%d\n", i); break;}
}
if(!flag) puts("No Solution");
}
return 0;
}