最近觉得图论的很多题目都是难在建模。。。这题虽然是比较明显的差分约束但是一直没能建出不等式模型,后来在搜索相关资料的时候看到了建模方法,在纠结了一阵子之后终于干掉了。
首先我们设定三个数组num[i](i时刻能够开始工作的人数)、s[i](实际雇佣的人数到i之和)、r[i](i时刻至少需要的人数)
那么可以直观的得出以下几个不等式:
(1)、0 <= s[i]-s[i-1]<=num[i];(i>=1 && i <= 24)
(2)、s[i] - s[i-8] >= r[i];(i >= 8 && i <= 24)
(3)、s[23] - (s[i+16] - s[i]) >= r[i];(i>=1 && i < 8)
第三个式子移项后可得s[i+16]-s[i] <= s[24] - r[i];
可以发现,如果我们设定s为未知量求解差分约束方程则s[24]为未知量,那么定然无法求解,因而需要枚举s[24]从0~m,如果这样的话有可能枚举到的结果j小于s[24],所以要增加一个新的约束s[24]>=j,即增加边24->0;为了防止负数和死循环,最好数组下标从1开始
#include <iostream>
#include <string.h>
using namespace std;
const int MAXN = 30;
const int MAXM = MAXN*MAXN;
int num[25], s[25], r[25];//i时刻能够开始工作的人数、实际雇佣的人数到i之和、至少需要的人数;
struct node
{
int v, w, next;
}mapp[MAXM];
int id;
int head[MAXN];
void init()
{
memset(head, -1, sizeof(head));
id = 0;
}
void addedge(int u, int v, int value)
{
mapp[id].v = v, mapp[id].w = value, mapp[id].next = head[u], head[u] = id ++;
}
int dist[MAXN];
bool inque[MAXN];
const int inf = 1 << 30;
int in[MAXN] = {0};
int que[100*MAXN];
bool SPFA(int s, int n)
{
memset(inque, false, sizeof(inque));
memset(in, 0, sizeof(in));
for (int i = 0; i <= n; i ++){
dist[i] = inf;
}
int front, rear;
front = rear = 0;
que[rear ++] = s;
inque[s] = true;
dist[s] = 0;
in[s] = 1;
while (front < rear){
int pre = que[front ++];
inque[pre] = false;
for (int i = head[pre]; i != -1; i = mapp[i].next){
if (dist[mapp[i].v] > dist[pre] + mapp[i].w){
dist[mapp[i].v] = dist[pre] + mapp[i].w;
if (!inque[mapp[i].v]){
inque[mapp[i].v] = true;
in[mapp[i].v] ++;
que[rear ++] = mapp[i].v;
if (in[mapp[i].v] > 24)return false;//判断是否有无解情况,因为每个点最多入队24次
}
}
}
}
return true;
}
int main()
{
int t;
scanf("%d", &t);
while ( t --){
for (int i = 1; i <= 24; i ++){
scanf("%d", &r[i]);
}
int m;
scanf("%d", &m);
memset(num, 0, sizeof(num));
for (int i = 0; i < m; i ++){
int time;
scanf("%d", &time);
num[time+1] ++;
}
init();
int minn = -1;
for (int j = 0; j <= m; j ++){
init();
for (int i = 1; i <= 24; i ++){
addedge(i-1, i, num[i]);
addedge(i, i-1, 0);
if (i >= 8 && i <= 24)
addedge(i, i-8, -r[i]);
else addedge(i, i+16, j-r[i]);
}
addedge(24, 0, -j);
if (SPFA(0, 25)){minn = j;break;}
}
minn == -1 ?printf("No Solution\n") : printf("%d\n", minn);
}
return 0;
}