POJ 1364 King(差分约束系统)

题意:给出n个变量,m个约束公式 asi + asi+1 + .... + asi+ni < ki or > ki ,叫你判断是否存在着解满足这m组约束公式。

题解:对于 asi + asi+1 + ....... + asi + n < ki or > ki,因为ai和ki都为整,设sum[n] 为 变量ai的前n个和,则可以转化为 sum[si+n] - sum[si-1] <= ki -1 or sum[si-1] - sum[si+n] <= -1-ki ,这样问题就转化为差分约束的情况。体会了差分约束系统的两个性质。第一就是处理的只能是>=或者<=。第二就是差分约束系统的解可以平移。开始做这题的时候就没注意到题中是>和<。另外就是Spfa判断负权回路时需要入队次数>=顶点数。

PS:差分约束根本不需要什么附加顶点, 附加顶点的唯一用处就是保证图的连通性, 不让你有负环判不到的情况, 解决这种问题的最佳途径就是初始把所有顶点都加入队列, 并且将所有dis置0, 这就相当于加了一个不存在的附加顶点, 它与所有的顶点的直连长度都是0. 但是注意在判负环时必须是"cnt>n"而不是"cnt>=n", 因为第一次所有顶点入队只是相当于把一个附加顶点加入到队列中而已, 不应该算在cnt中, 如果在此步骤没有增加过cnt, 则">="也是可以的。

#include <iostream>
using namespace std;

#define N  150
#define INF 9999999

int n, m, size;
bool mark[N];
int head[N], dis[N];
int que[N], inque[N];

struct Edge { int v, w, next; };
Edge  edge[N];

bool Spfa()
{
	memset(mark,0,sizeof(mark));
	memset(inque,0,sizeof(inque));
	for ( int i = 0; i <= n+1; i++ )
		dis[i] = INF;

	int u, v, front, rear;
	front = rear = 0;
	mark[n+1] = true;
	inque[n+1]++;
	dis[n+1] = 0;
	que[rear] = n+1;
	rear = ( rear + 1 ) % N;

	while ( front != rear )
	{
		u = que[front];
		front = ( front + 1 ) % N;
		mark[u] = false;
		for ( int i = head[u]; i; i = edge[i].next )
		{
			v = edge[i].v;
			if ( dis[v] > dis[u] + edge[i].w )
			{
				dis[v] = dis[u] + edge[i].w;
				if ( ! mark[v] )
				{
					que[rear] = v;
					rear = ( rear + 1 ) % N;
					mark[v] = true;
					inque[v]++;
					if ( inque[v] >= n+2 ) return false;
					
				}
			}
		}
	}
	return true;
}

void add ( int u, int v, int w )
{
	size++;
	edge[size].v = v;
	edge[size].w = w;
	edge[size].next = head[u];
	head[u] = size;
}

int main()
{
	char oper[5];
	int a, b, c;
	while ( scanf("%d",&n) && n  )
	{
		scanf("%d",&m);
		size = 0;
		memset(head,0,sizeof(head));

		while ( m-- )
		{
			scanf("%d %d %s %d",&a,&b,&oper,&c);
			if ( oper[0] == 'g' )
				add ( a+b, a-1, -(c+1) );
			else
				add ( a-1, a+b, c-1 );
		}

		for ( int i = 0; 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、付费专栏及课程。

余额充值