poj 1364 差分约束(笨国王求序列)

题意:考虑一个长度为n的序列是否存在,其中序列为S={a1,a2,a3,a4...ai...an},现在给出m个不等式,需要满足ai+a(i+1)+a(i+2)+...+a(i+n)<ki或者是ai+a(i+1)+a(i+2)+...+a(i+n)>ki。不等式如下描述:四个参数,其中第一个数i代表序列从第几项开始,第二个数n表示i后面有n个数(也即序列长为n+1,从a(i)...a(i+n)),第三个参数表示大于或者小于,第四个是数值。当符号为gt代表‘>’,符号为lt代表‘<'。样例意思为:
1 2 gt 0
a1+a2+a3>0
2 2 lt 2
a2+a3+a4<2

最后问满足所有不等式的序列是否存在,若满足输出lamentable kingdom,不满足输出successful conspiracy。


思路:差分约束。首先设Si=a1+a2+a3+...+ai,那么根据样例可以得出:
S3-S0>0---->S0-S3<=-1,
S4-S1<2---->S4-S1<=1。
因为差分约束的条件是小于等于,所以我们将小于号右边的数值-1可以将题意的小于变成小于等于。那么通式可以表示为
a  b  gt  c
S[a-1]-s[a+b]<=-ki-1
a  b  lt  c
S[a+b]-S[a-1]<=ki-1
接下来根据差分约束建图,加入这些有向边
gt:  <a+b,a-1>=-ki-1
lt:  <a-1,a+b>=ki-1
再根据spfa(或者bellman_ford)判断是否有无负环即可,若出现负环了则这个序列不满足所有的不等式。

需要注意1、用spfa判断负环的时候要加入一个新节点,其与所有节点连边,权值为0。此题中新节点不能够用节点0,因为0节点在之前建图中可能已经用到(a和b虽然从1开始,但是建图时有插入a-1的可能)。所以新节点要用n+1号。2、spfa判断负环是在num数组值加一之后,不是放在队列为空之后统一判断,因为如果有负环队列可能根本就出不来。

#include <stdio.h>
#include <string.h>
#define INF 0x3fffffff
#define N 115
struct edge{
	int y,next,w;
}e[1000];
int n,m;
char op[5];
int num[N],first[N],dis[N],top,q[100000];
void add(int x,int y,int w){
	e[top].y = y;
	e[top].w = w;
	e[top].next = first[x];
	first[x] = top++;
}
int relax(int x,int y,int w){
	if(dis[x] + w < dis[y]){
		dis[y] = dis[x] + w;
		return 1;
	}
	return 0;
}
int spfa(){
	int i,now,used[N],front,rear;
	memset(used,0,sizeof(used));
	memset(num,0,sizeof(num));
	used[n+1] = 1;
	dis[n+1] = 0;
	for(i = 0;i<=n;i++)
		dis[i] = INF;
	front = rear = -1;
	q[++rear] = n+1;
	while(front < rear){
		now = q[++front];
		used[now] = 0;
		for(i = first[now];i!=-1;i=e[i].next)
			if(relax(now,e[i].y,e[i].w) && !used[e[i].y]){
				q[++rear] = e[i].y;
				used[e[i].y] = 1;
				num [e[i].y]++;
				if(num[e[i].y] > n)
					return 0;
			}
	}
	return 1;
}
int main(){
	freopen("a.txt","r",stdin);
	while(scanf("%d",&n) && n){
		int i,a,b,c;
		top=0;
		memset(first,-1,sizeof(first));
		scanf("%d",&m);
		for(i = 0;i<m;i++){
			scanf("%d %d %s %d",&a,&b,op,&c);
			if(!strcmp(op,"gt"))
				add(a+b,a-1,-c-1);
			else
				add(a-1,a+b,c-1);
		}
		for(i = 1;i<=n;i++)
			add(n+1,i,0);
		if(spfa())
			printf("lamentable kingdom\n");
		else
			printf("successful conspiracy\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值