ZOJ2770 Burn the Linked Camp,差分约束

本文介绍了一种利用差分约束解决最小值问题的方法。通过定义变量和建立差分不等式,使用SPFA算法求解最长路径来找到目标最小值。文章详细解释了如何根据题目条件设置边和权重,并通过具体代码实现展示了整个求解过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个是典型的差分约束题,解题可以看代码开头的注释


/*******************************************************************************
 # Author : Neo Fung
 # Email : neosfung@gmail.com
 # Last modified: 2011-10-05 20:03
 # Filename: ZOJ2770 Burn the Linked Camp.cpp
 # Description : 
	差分约束,我们定义x[i]为第i个营的人数,定义dist[i]=x[0]+x[1]+...x[i],其中x[0]=0,则可知我们要求的为dist[n]。
	对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值;对于不等式 a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值。这题由于求最小值,所以我们用的是第二种。
	对于题目,我们可以有如下约束
	Ci有: x[i]=dist[i]-dist[i-1],则有dist[i]-dist[i-1]>=0,且dist[i-1]-dist[i]>=-Ci
	i,j,k有: s[j]-s[i-1]>=k
	还有: dist[i]>=0,即dist[i]-dist[0]>=0
	因为是求最小值,同时图的建立是按照小于等于进行,所以我们就要从负无穷约束到最小值,用SPFA求最长路即可。
	SPFA过程中判断是否有环。
 ******************************************************************************/
// #include "stdafx.h"
// #define DEBUG

#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <memory.h>
#include <limits.h>
#include <queue>
#define MAX 1010
using namespace std;

struct NODE{
	int to,len;
	NODE *next;
}node[MAX*MAX],*apex[MAX];

int nodeInd,dist[MAX],n,m;
void init()
{
	nodeInd=0;
	memset(apex,'\0',sizeof(apex));
}

void add(int u,int v,int len)
{
	node[nodeInd].to=v;
	node[nodeInd].len=len;
	node[nodeInd].next=apex[u];
	apex[u]=&node[nodeInd++];
}

int spfa()
{
	queue<int> myqueue;
	int inque[MAX],time[MAX];
	memset(inque,0,sizeof(inque));
	memset(time,0,sizeof(time));
	myqueue.push(0);
	time[0]=inque[0]=1;
	for (int i=1;i<=n;++i)
		dist[i]=INT_MIN;
	dist[0]=0;
	while(!myqueue.empty())
	{
		int x=myqueue.front();
		myqueue.pop();
		inque[x]=0;
		NODE *head=apex[x];
		while(head)
		{
			int to=head->to;
			int len=head->len;
			if(dist[to]<dist[x]+len)
			{
				dist[to]=dist[x]+len;
				if(inque[to]==0)
				{
					myqueue.push(to);
					inque[to]=1;
					if(++time[to]>n)
						return -1;
				}
			}
			head=head->next;
		}
	}
	return dist[n];
}

int main(void)
{
#ifdef DEBUG  
	freopen("data.txt","r",stdin);  
#endif  
	int u,v,len;

	while(scanf("%d %d",&n,&m)!=EOF)
	{
		init();
		for(int i=1;i<=n;++i)
		{
			scanf("%d",&len);
			add(i-1,i,0);
			add(i,i-1,-len);
			add(0,i,0);
		}
		for(int i=0;i<m;++i)
		{
			scanf("%d %d %d",&u,&v,&len);
			add(u-1,v,len);
		}
		int ans=spfa();
		if(ans==-1)
			printf("Bad Estimations\n");
		else
			printf("%d\n",ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值