题意:给定N个任务,每个任务有一个完成时间。这些任务之间有完成的四种先后顺序,假设这种二元关系建立在x,y之间:
SAS:x至少在y开始时开始
SAF:x至少在y完成时开始
FAS:x至少在y开始时完成
FAF:x至少在y完成时完成
现在问这些任务在最短时间内都被完成的任务安排如何?输出每个任务开始的时刻,如果不能的话输出impossible。
解法:根据开始时间建图,之后再虚拟出一个任务0,这个任务必须在每个任务完成后完成,因此在0到每个任务之间添加一条边,最后计算出所有节点中到0点最迟的开始的任务,设该任务0点开始,并让每个任务的开始时间都加上这个时间差。
代码如下:
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; int ti[1005]; int N, idx, head[1005]; struct Edge { int v, ct, next; }e[1000005]; void insert(int a, int b, int ct) { e[idx].v = b, e[idx].ct = ct; e[idx].next = head[a]; head[a] = idx++; } int vis[1005], dis[1005], cnt[1005]; #include <queue> bool spfa() { memset(vis, 0, sizeof (vis)); memset(cnt, 0, sizeof (cnt)); memset(dis, 0x3f, sizeof (dis)); queue<int>q; q.push(0); vis[0] = 1, dis[0] = 0, cnt[0] = 1; while (!q.empty()) { int v = q.front(); q.pop(); if (cnt[v] > N) return false; vis[v] = 0; for (int i = head[v]; i != -1; i = e[i].next) { if (dis[e[i].v] > dis[v] + e[i].ct) { dis[e[i].v] = dis[v] + e[i].ct; if (!vis[e[i].v]) { vis[e[i].v] = 1; ++cnt[e[i].v]; q.push(e[i].v); } } } } return true; } void solve() { int Min = ~(1<<31), p; for (int i = 1; i <= N; ++i) { if (Min > dis[i]) { Min = dis[i]; p = i; } } for (int i = 1; i <= N; ++i) { printf("%d %d\n", i, dis[i]-dis[p]); } } int main() { char op[10]; int a, b, kind, ca = 0; while (scanf("%d", &N), N) { memset(head, 0xff, sizeof (head)); idx = 0; for (int i = 1; i <= N; ++i) { scanf("%d", &ti[i]); insert(0, i, -ti[i]); } while (scanf("%s", op), op[0] != '#') { kind = op[0] == 'S' ? 0 : 1; kind |= op[2] == 'S' ? 0 : 2; scanf("%d %d", &a, &b); if (kind == 0) insert(a, b, 0); else if (kind == 1) insert(a, b, ti[a]); else if (kind == 2) insert(a, b, -ti[b]); else insert(a, b, ti[a]-ti[b]); } printf("Case %d:\n", ++ca); if (!spfa()) { puts("impossible\n"); continue; } solve(); puts(""); } return 0; }