题意:好毒瘤的题面啊。。。
就是有一个长度N的序列S = {a1,a2,...,an},现在有M个约束条件,每个约束条件包含三个数字s, n, k和一个用来表示大于号(gt)或小于号(lt)的串o,表示 或 ,'>' 还是 '<' 取决于串o。问这m个条件能够同时得到满足。
思路:可以看出每个约束都是S的一个子序列的和与k的关系,记Si为S中前i个元素的和,则可以将原来的不等式转换为 或 ,即变成了差分约束求解的存在性问题,用最长路和最短路求都可以。这里用spfa跑最短路判负环。
因为题目中给的图不一定是连通的,所有需要加一个到所有结点的边权都是0的超级源点,这一步通过预先将所有元素加入队列来完成。
#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 = 105;
struct edg{
int v, d, nxt;
}G[maxn];
int pre[maxn], tot, dis[maxn], times[maxn];
bool vis[maxn];
int n, m;
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 spfa() {
queue<int> que;
for (int i = 0; i <= n; ++i) {
vis[i] = 1;
que.push(i); //预先将结点都加入队列,代替超级源点的功能
dis[i] = inf;
times[i] = 1;
}
dis[0] = 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 a, b, k;
char str[5];
while (~scanf("%d", &n) && n) {
tot = 0;
memset(pre, -1, sizeof(pre));
scanf("%d", &m);
while (m--) {
scanf("%d%d%s%d", &a, &b, str, &k);
if (str[0] == 'g') {
add(a + b, a - 1, -k - 1);
} else {
add(a - 1, a + b, k - 1);
}
}
puts(spfa() ? "lamentable kingdom" : "successful conspiracy");
}
return 0;
}