题意
给你一个序列,S={a1,a2,……an},然后给你一些信息,判断是否存在解满足题目给的一些不等式的条件。gt表示>,lt表示<(注意是大于和小于,不是大于等于和小于等于).
比如题目给出的例子
4 2 (4个元素,2个不等式条件)
1 2 gt 0 表示a1+a2+a3>0,
2 2 lt 2 表示 a2+a3+a4<2,
首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单直接减1…(来自dalao的说法,当初我以为只要是不等式的条件就可以差分约束了,结果差分约束系统的适用范围是处理大于等于,小于等于的情况)。
设s[i]为数组的前缀和。
大于的情况为
s[u+v]-s[u-1]>k;
那么我们可以转化为s[u-1]-s[u+v]
//全部放进队列的写法
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int MAXN=1e2+7;
const int MAXM=1e2*3+7;
struct node
{
int to,next,w;//其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.
}Edge[MAXM];//Edge保持m条边的个数
int head[MAXM];
int dis[MAXN];
int num[MAXN];
bool vis[MAXN];
int n,m,tot;//head和dis保持n个点
void add_edge(int a,int b,int c)
{
Edge[++tot].to=b;
Edge[tot].w=c;
Edge[tot].next=head[a];
head[a]=tot;
}
int SPFA(int s)
{
queue<int>q;
int k,to,w;
memset(num,0,sizeof(num));
memset(vis,false,sizeof(vis));
//首先这个题的 Si...sn我的写法会从0开始的....所以如果用超级源点..不能用0点(WA了一个小时看了别人的说法才知道是多么痛的领悟)..所以我干脆就没用超级点...学别人直接开始的时候把所有点入队~~效果是一样的
for(int i=0;i<=n;i++)
{
dis[i]=0;
num[i]=0;//ORZ这里如果num[i]=1的话,UVA就WA,改成0就过了
vis[i]=true;
q.push(i);
}
//为什么不像之前那样写,因为这道题涉及0点(超级源点要与题目给的任何点或者范围无关才可以,不然会影响结果),
//所以我们换种写法,直接把所有点都放进去队列,dis大小也是0(表示超级源点到任何点的距离都为0)。这样就可以得出答案了。
while(!q.empty())
{
k=q.front();
q.pop();
vis[k]=0;//弹出队列并取消标记
for(int i=head[k];i!=-1;i=Edge[i].next)
{
to=Edge[i].to;
w=Edge[i].w;
if(dis[k]+w<dis[to])
{
dis[to]=dis[k]+w;
if(!vis[to])//判断这个点是否在队列里面,如果不在加入队列
{
vis[to]=true;
q.push(to);
num[to]++;
if(num[to]>n)//判断是否成环
return -1;
}
}
}
}
return 1;
}
int main()
{
while(~scanf("%d",&n),n)
{
scanf("%d",&m);
memset(head,-1,sizeof(head));
tot=1;
for(int i=1;i<=m;i++)
{
char c[5];
int u,v,w;
scanf("%d%d%s%d",&u,&v,c,&w);
if(c[0]=='g')//大于
add_edge(v+u,u-1,-w-1);
else//小于
add_edge(u-1,v+u,w-1);
}
int ans=SPFA(0);
if(ans==-1)
printf("successful conspiracy\n");
else
printf("lamentable kingdom\n");
}
return 0;
}
//首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单= =
//如果题目给的是<,>而不是<=,>=的话,就将<,>变成<=,>=.比如A-B<1变成A-B<=0.
//n+1作为超级源点的写法
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int MAXN=1e2+7;
const int MAXM=1e2*3+7;
struct node
{
int to,next,w;//其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.
}Edge[MAXM];//Edge保持m条边的个数
int head[MAXM];
int dis[MAXN];
int num[MAXN];
bool vis[MAXN];
int n,m,tot;//head和dis保持n个点
void add_edge(int a,int b,int c)
{
Edge[++tot].to=b;
Edge[tot].w=c;
Edge[tot].next=head[a];
head[a]=tot;
}
int SPFA(int s)
{
queue<int>q;
int k,to,w;
memset(num,0,sizeof(num));
memset(vis,false,sizeof(vis));
for(int i=0;i<=n;i++)
dis[i]=INF;
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
k=q.front();
q.pop();
vis[k]=false;//弹出队列并取消标记
for(int i=head[k];i!=-1;i=Edge[i].next)
{
to=Edge[i].to;
w=Edge[i].w;
if(dis[k]+w<dis[to])
{
dis[to]=dis[k]+w;
if(!vis[to])//判断这个点是否在队列里面,如果不在加入队列
{
vis[to]=true;
q.push(to);
num[to]++;
if(num[to]>n)//判断是否成环
return -1;
}
}
}
}
return 1;
}
int main()
{
while(~scanf("%d",&n),n)
{
scanf("%d",&m);
memset(head,-1,sizeof(head));
tot=1;
for(int i=1;i<=n;i++)
add_edge(n+1,i,0);
for(int i=1;i<=m;i++)
{
char c[5];
int u,v,w;
scanf("%d%d%s%d",&u,&v,c,&w);
if(c[0]=='g')//大于
add_edge(v+u,u-1,-w-1);
//如果用add_edge(v+u,u-1,-w-1)的话会错的,因为用SPFA要用超级源点保证图的连通性,但是(注意了)(v+u,u-1,-w-1)说明会出现0,
//而你用0作为源点,就会影响结果。所以只能是(v+u+1,u,-w-1)
else//小于
add_edge(u-1,v+u,w-1);
}
int ans=SPFA(n+1);
if(ans==-1)
printf("successful conspiracy\n");
else
printf("lamentable kingdom\n");
}
return 0;
}
//首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单= =
//如果题目给的是<,>而不是<=,>=的话,就将<,>变成<=,>=.比如A-B<1变成A-B<=0.
//可以用0作为超级源点的写法
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int MAXN=1e2+7;
const int MAXM=1e2*3+7;
struct node
{
int to,next,w;//其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.
}Edge[MAXM];//Edge保持m条边的个数
int head[MAXM];
int dis[MAXN];
int num[MAXN];
bool vis[MAXN];
int n,m,tot;//head和dis保持n个点
void add_edge(int a,int b,int c)
{
Edge[++tot].to=b;
Edge[tot].w=c;
Edge[tot].next=head[a];
head[a]=tot;
}
int SPFA(int s)
{
queue<int>q;
int k,to,w;
memset(num,0,sizeof(num));
memset(vis,false,sizeof(vis));
for(int i=0;i<=n+1;i++)//因为是(v+u+1,u,-w-1),所以n要加1.
dis[i]=INF;
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
k=q.front();
q.pop();
vis[k]=false;//弹出队列并取消标记
for(int i=head[k];i!=-1;i=Edge[i].next)
{
to=Edge[i].to;
w=Edge[i].w;
if(dis[k]+w<dis[to])
{
dis[to]=dis[k]+w;
if(!vis[to])//判断这个点是否在队列里面,如果不在加入队列
{
vis[to]=true;
q.push(to);
num[to]++;
if(num[to]>n)//判断是否成环
return -1;
}
}
}
}
return 1;
}
int main()
{
while(~scanf("%d",&n),n)
{
scanf("%d",&m);
memset(head,-1,sizeof(head));
tot=1;
for(int i=1;i<=n;i++)
add_edge(0,i,0);
for(int i=1;i<=m;i++)
{
char c[5];
int u,v,w;
scanf("%d%d%s%d",&u,&v,c,&w);
if(c[0]=='g')//大于
add_edge(v+u+1,u,-w-1);
//如果用add_edge(v+u,u-1,-w-1)的话会错的,因为用SPFA要用超级源点保证图的连通性,但是(注意了)(v+u,u-1,-w-1)说明会出现0,
//而你用0作为源点,就会影响结果。所以只能是(v+u+1,u,-w-1)
else//小于
add_edge(u,v+u+1,w-1);
}
int ans=SPFA(0);
if(ans==-1)
printf("successful conspiracy\n");
else
printf("lamentable kingdom\n");
}
return 0;
}
//首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单= =
//如果题目给的是<,>而不是<=,>=的话,就将<,>变成<=,>=.比如A-B<1变成A-B<=0.