poj 1275 Cashier Employment 差分约束
这题的不等式比较难列,列了很久,也列不全,对那个8小时理解的不透。
设num[i] 为来应聘的在第i个小时开始工作的人数
r[i] 为第i个小时至少需要的人数
x[i] 为招到的在第i个小时开始工作的人数
根据题意有:
0 <= x[i] <= num[i]
x[i] + x[i-1] + …+ x[i-7] >= r[i] (题目中的连续工作8小时)
再设 s[i] = x[1] + … + x[i]
则有: s[i] – s[i-1] >= 0
s[i-1] – s[i] >= –num[i]
s[i] – s[i-8] >= r[i], 8 <= i <= 24
s[i] – s[i+16] >= r[i] – s[24], 1<= i <= 7
还需要添加一个隐藏不等式: s[24] – s[0] >= ans(枚举的答案)
通过枚举s[24],来检测是否满足条件,题目是求最小值,即求最长路,以0为源点。
#include <iostream> #include <queue> using namespace std; const int N = 30; const int MAX = 10000; const int INF = 1000000000; struct Node { int v; int cost; int next; }; Node node[MAX]; queue<int> Q; int adj[N]; int num[N]; int size; int r[N]; int s[N]; int cnt[N]; bool in_q[N]; void add_edge(int u, int v, int cost) { node[size].v = v; node[size].cost = cost; node[size].next = adj[u]; adj[u] = size++; } bool spfa(int ans) { for (int i = 0; i <= 24; i++) { s[i] = -INF; cnt[i] = 0; in_q[i] = false; } while (!Q.empty()) Q.pop(); int u, v, w; s[0] = 0; Q.push(0); in_q[0] = true; while (!Q.empty()) { u = Q.front(); Q.pop(); in_q[u] = false; for (int i = adj[u]; i != -1; i = node[i].next) { v = node[i].v; w = node[i].cost; if (s[v] < s[u] + w) { s[v] = s[u] + w; if (!in_q[v]) { in_q[v] = true; Q.push(v); if (++cnt[v] > 24) return false; } } } } if (s[24] == ans) return true; else return false; } int main() { int cases; int n, c; bool has_solution; cin >> cases; while (cases--) { for (int i = 1; i <= 24; i++) { scanf("%d", &r[i]); num[i] = 0; } cin >> n; for (int i = 0; i < n; i++) { scanf("%d", &c); num[c+1]++; } int ans; for ( ans = 0; ans <= n; ans++) { size = 0; has_solution = false; for (int i = 0; i <= 24; i++) adj[i] = -1; for (int i = 1; i <= 24; i++) { add_edge(i-1, i, 0); add_edge(i, i-1, -num[i]); if (i >= 8) add_edge(i-8, i, r[i]); } for (int i = 1; i <= 7; i++) add_edge(i+16, i, r[i]- ans); add_edge(0, 24, ans); if (spfa(ans)) { has_solution = true; break; } } if (has_solution) printf("%d\n", ans); else printf("No Solution\n"); } return 0; }