HDU1534 Schedule Problem(差分约束)

题意:一个项目可以分为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");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/hcx11333/article/details/81406751