题目链接:http://210.32.0.220/onlinejudge/showProblem.do?problemCode=1455
典型的差分约束题目, 不等式很好列但此题求的是满足约束的最小值, 原来看到网上有最大值求最短路, 最小值求最长路的说法但本人觉得有点烦, 所以都转化成求最短路, 所以要求加负号的最大值, 注意超级点的确立, 细节详见代码。
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;
const int N = 5005;
const int M = N << 4;
const int INF = 1000000000;
struct SPFA {
struct Edge {
int v, w;
Edge* next;
void init(int a, int b, Edge* e) {
v = a, w = b, next = e;
}
};
Edge E[M], * head[N], * it;
bool inq[N];
int cnt[N];
queue<int> Q;
int tot, n;
int dis[N];
void init(int n) {
this->n = n;
it = E;
for (int i = 0; i < n; i++) {
head[i] = 0;
}
}
void add(int u, int v, int w) {
it->init(v, w, head[u]);
head[u] = it++;
}
bool run(int s) {
for (int i = 0; i < n; cnt[i] = 0, inq[i] = 0, dis[i++] = INF);
dis[s] = 0;
Q.push(s);
cnt[s] = 1;
while (!Q.empty()) {
int u = Q.front();
inq[u] = 0;
Q.pop();
for (Edge* e = head[u]; e; e = e->next) {
int v = e->v;
if (dis[v] > dis[u] + e->w) {
dis[v] = dis[u] + e->w;
if(!inq[v]) {
Q.push(v);
inq[v] = 1;
cnt[v]++;
if (cnt[v] > n) return 0;
}
}
}
}
return 1;
}
}G;
char op[10];
int main() {
int n, u, v, w, cas = 1;
while (scanf("%d", &n), n) {
int s = 0;
G.init(2 * n + 1);
for (int i = 1; i <= n; i++) {
scanf("%d", &w);
G.add(i + n, i, -w);
G.add(i, i + n, w);
}
for (int i = 1; i <= n; i++)
G.add(s, i + n, 0);
while (scanf("%s", op)) {
if (op[0] == '#') break;
scanf("%d%d", &u, &v);
if (strcmp(op, "FAS") == 0) {
G.add(u + n, v, 0);
}
else if (strcmp(op, "FAF") == 0) {
G.add(u + n, v + n, 0);
}
else if (strcmp(op, "SAF") == 0) {
G.add(u, v + n, 0);
}
else {
G.add(u, v, 0);
}
}
printf("Case %d:\n", cas++);
int st = INF;
if (!G.run(s)) {
puts("impossible\n");
}
else {
for (int i = 1; i <= n; i++)
st = min(st, G.dis[i]);
for (int i = 1; i <= n; i++) {
printf("%d %d\n", i, G.dis[i] - st);
}
puts("");
}
}
return 0;
}