题意: 问是否存在长度为n的序列满足m个条件. 每个条件描述某一段子序列和大于或者小于k.
转化前缀:
su−sv−1<k
或者
su−sv−1>k
, 因为都是整数, 把k用k-1替换改成
≤
和
≥
, 然后就是差分式子了. 可以不用加超级源点, 因为关心的是负环是否存在, 所以初始把每一个点都加近队列就好了.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define INF 1111111111
#define maxn 1005
int n, m;
struct node {
int v, next;
int w;
}edge[maxn];
int head[maxn], cnt;
void init () {
memset (head, -1, sizeof head);
cnt = 0;
}
void add_edge (int u, int v, int w) {
edge[cnt].v = v, edge[cnt].next = head[u], edge[cnt].w = w, head[u] = cnt++;
}
bool vis[maxn];
int top, num[maxn];
double d[maxn];
bool spfa (int n) {
queue <int> q;
while (!q.empty ()) q.pop ();
memset (num, 0, sizeof num);
for (int i = 0; i < n; i++) {
vis[i] = 1;
d[i] = 0;
q.push (i);
num[i] = 1;
}
while (!q.empty ()) {
int u = q.front (); q.pop ();
vis[u] = 0;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (d[v]>d[u]+edge[i].w) {
d[v] = d[u]+edge[i].w;
if (!vis[v]) {
vis[v] = 1;
q.push (v);
if (++num[v] > n)
return 0;
}
}
}
}
return 1;
}
char op[11];
int main () {
while (scanf ("%d%d", &n, &m) == 2 && n) {
init ();
for (int i = 0; i < m; i++) {
int v, len, k;
scanf ("%d%d", &v, &len);
int u = v+len;
scanf ("%s%d", op, &k);
if (op[0] == 'g') {
add_edge (u, v-1, -k-1);
}
else {
add_edge (v-1, u, k-1);
}
}
if (spfa (n+1))
printf ("lamentable kingdom\n");
else
printf ("successful conspiracy\n");
}
return 0;
}