题意:和上一题比较像,不过这里不是根据已知的约束求出另外一个约束,而是判定是否存在解。给定一个区间的和值区间,问整个区间能否满足所有的要求。
解法:虚拟一个超级源点,超级源点到点i的最短路表示到第i个数时总和为dis[i],为了保证每个点能够被计算到,那么需要从超级源点连一条没有什么影响的边出来。然后对整个图求一次spfa,观察是否存在负环。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int N, M, idx; int head[105]; const int T = 102; // 超级源点 struct Edge { int v, ct, next; }e[505]; void insert(int a, int b, int ct) { e[idx].v = b, e[idx].ct = ct; e[idx].next = head[a]; head[a] = idx++; } #include <queue> int dis[105], cnt[105]; char vis[105]; bool spfa() { memset(dis, 0x3f, sizeof (dis)); memset(cnt, 0, sizeof (cnt)); memset(vis, 0, sizeof (vis)); queue<int>q; q.push(T); cnt[T] = 1, vis[T] = 1, dis[T] = 0; while (!q.empty()) { int v = q.front(); q.pop(); vis[v] = 0; if (cnt[v] > N+5) return false; 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]) { q.push(e[i].v); ++cnt[e[i].v]; vis[e[i].v] = 1; } } } } return true; } int main() { int a, b, c; char op[5]; while (scanf("%d", &N), N) { idx = 0; memset(head, 0xff, sizeof (head)); scanf("%d", &M); for (int i = 0; i < M; ++i) { scanf("%d %d %s %d", &a, &b, op, &c); if (op[0] == 'g') { // dis[b] - dis[a-1] >= c+1 insert(a+b, a-1, -c-1); } else { // dis[b] - dis[a-1] <= c-1 insert(a-1, a+b, c-1); } } for (int i = 0; i <= N; ++i) { insert(T, i, rand() % 1000); // 引入一条从超级源点到任意一点的0边,这个约束条件对题解没有影响 } if (spfa()) { puts("lamentable kingdom"); } else { puts("successful conspiracy"); } } return 0; }