题意:给你一个n和m,接下来m行,每行描述了一个不等式,每行有个a,b,一个符号,c,如果字符串为gt,就代表某个数列的[a,b]的和大于c,如果字符串为lt,就代表某个数列的[a,b]的和小于c,然后问你上述条件能不能同时成立,不能输出successful conspiracy,能输出lamentable kingdom。
思路:将这些条件都转化为标准的差分约束的不等式,然后建图,判断有没有负环,有就是不能,没有就是可以。
说下我之前纠结的为什么有负环就证明不能满足条件,假如有三条边a->b = x,b->c = y,c->a = z,转化成不等式就是sa<=sc+z,sc<=sb+y,sb<=sa+x,然后把左右相加,约掉一堆东西,得到0<=x+y+z,如果出现负环,那么x+y+z<0可以得出不满足条件。。也许是悟性太差,不能一下理解。。所以自己小证了一下=。=
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 200;
const int inf = 0x3f3f3f3f;
int n,m,all;
int node[maxn],top;
struct Side{
int v,w,next;
}side[maxn];
void add_side(int u,int v,int w){
side[top] = (Side){v,w,node[u]};
node[u] = top++;
}
int dis[maxn],vis[maxn],in[maxn];
bool done[maxn];
queue<int>q;
int spfa(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
dis[s] = 0;in[s] = 1;
q.push(s);
while(!q.empty()){
int u = q.front();q.pop();
vis[u] = 0;done[u] = 1;
for(int i = node[u];i != -1;i = side[i].next){
int v = side[i].v;
if(dis[v] > dis[u] + side[i].w){
dis[v] = dis[u] + side[i].w;
if(!vis[v]){
in[v] ++;
if(in[v] > all)return -1;
vis[v] = 1;
q.push(v);
}
}
}
}
return 1;
}
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n),n){
memset(node,-1,sizeof(node));
memset(done,false,sizeof(done));
top = 0;
scanf("%d",&m);
int nn[maxn] = {0};
all = 0;//记录共有几个节点
while(m--){
int a,b,c;
char op[5];
scanf("%d %d %s %d",&a,&b,op,&c);
if(op[0] == 'g'){
add_side(a+b,a-1,-1-c);
nn[a-1] = nn[a + b] = 1;
}
else if(op[0] == 'l'){
add_side(a-1,b+a,c-1);
nn[a + b] = nn[a - 1] = 1;
}
}
int ans;
for(int i = 0;i <= n;i ++)
if(nn[i])all ++;
for(int i = 0;i <= n;i ++)
if(nn[i]&&done[i] == false){
ans = spfa(i);//说不定不连通。。
if(ans == -1)break;
}
if(ans == -1)printf("successful conspiracy\n");
else printf("lamentable kingdom\n");
}
return 0;
}