题意:一个项目可以分为N个部分,每个部分都有自己的工期,且互相可以并行地完成,一个部分一旦动工,就必须做完,不能中间暂停,同时可以开展的任务数没有上限。有4种约束条件:
FAS(i,j):i部分必须在j部分开始前完成。
FAF(i,j):i部分必须在j部分结束前结束。
SAF(i,j):i部分必须在j部分完成前开始。
SAS(i,j):i部分必须在j部分开始前开始。
要让总工期最短,输出每个部分开始的时间(从0开始计数),无解就输出"impossible"。
思路:显然可以建立差分约束系统,设Si为i部分开始的时间,di为i部分需要的天数,对于四种约束:
FAS(i,j):Si >= Sj - di
FAF(i,j):Si >= Sj + dj - di
SAF(i,j):Si >= Sj + dj
SAS(i,j):Si >= Sj
题目中的“after”一词没说明白,比如SAS(i,j)中i可以和j同一天开始,其他的同理,分析样例才看得出来。
因为要求Si - S0的最小值,建立虚拟源点0,开始时间为0,且在图中到每个点的边都是0,即SAS(i, 0),(i = 1,2,...,n)。
SPFA跑一遍最远路即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <cstdlib>
#include <set>
#include <string>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
struct edg{
int v, d, nxt;
}G[maxn];
int pre[maxn], tot, dis[maxn], times[maxn];
bool vis[maxn];
void add(int u, int v, int w) {
G[tot].v = v;
G[tot].d = w;
G[tot].nxt = pre[u];
pre[u] = tot++;
}
int n, days[maxn];
int spfa() {
memset(times, 0, sizeof(times));
memset(vis, 0, sizeof(vis));
for (int i = 0; i <= n; ++i) {
dis[i] = -inf;
}
queue<int> que;
dis[0] = 0;
vis[0] = true;
que.push(0);
while (!que.empty()) {
int u = que.front();
que.pop();
vis[u] = false;
for (int i = pre[u]; ~i; i = G[i].nxt) {
int v = G[i].v, w = G[i].d;
if (dis[u] + w > dis[v]) {
dis[v] = dis[u] + w;
if (!vis[v]) {
vis[v] = true;
if (++times[v] > n + 1) {
return false;
}
que.push(v);
}
}
}
}
return true;
}
int main(){
int u, v, cas = 0;
char str[5];
while (~scanf("%d", &n) && n) {
tot = 0;
memset(pre, -1, sizeof(pre));
for (int i = 1; i <= n; ++i) {
scanf("%d", &days[i]);
add(0, i, 0); // SAS(i, 0, 0);
}
while (~scanf("%s", str) && str[0] != '#') {
scanf("%d%d", &u, &v);
if (str[0] == 'F' && str[2] == 'F') {
add(v, u, days[v] - days[u]);
} else if (str[0] == 'F' && str[2] == 'S') {
add(v, u, -days[u]);
} else if (str[0] == 'S' && str[2] == 'F') {
add(v, u, days[v]);
} else {
add(v, u, 0);
}
}
printf("Case %d:\n", ++cas);
if (spfa()) {
for (int i = 1; i <= n; ++i) {
printf("%d %d\n", i, dis[i]);
}
puts("");
} else {
printf("impossible\n\n");
}
}
}