算法自学__差分约束算法

差分约束系统

如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj ≤ k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。

问题分析

我们对不等式进行简单的变形:
a i − a j ≤ k     ⟹     a i ≤ k + a j a_i-a_j\leq k\ \ \ \Longrightarrow \ \ \ a_i\leq k+a_j aiajk      aik+aj
我们将 a i a_i ai看作从起点到i点的最短距离,将 k k k看作由j点到i的边的权值。此时,求解差分约束系统就转化成了求解单源最短路的问题。

为了便于求解,我们设立一个新的结点 a 0 a_0 a0,然后建立 a 0 a_0 a0指向每个结点的权值为0的边。
我们以 a 0 a_0 a0为源点,求解源点到各个结点的最短距离,这些最短距离就构成了差分约束系统的一组解。

算法细节

由于边权值可正可负,所以我们不能采用迪克斯特拉算法。因此,我们采用SPFA算法。

由于 a 0 a_0 a0到各个节点的初始结点的距离为0,所以得到的解中的每个变量的取值一定 ≤ 0 \leq0 0

P5960 【模板】差分约束算法

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;

class EDGE{
public:
	int to;
	int w;
public:
	EDGE(int to,int w){
		this->to=to;
		this->w=w;
	}
};
vector<EDGE>graph[5005];
int n,m;
int a,b,y;
int ans[5005];
int cnt[5005];

bool SPFA(int s){
	memset(ans,127,sizeof(ans));
	memset(cnt,0,sizeof(cnt));
	queue<EDGE>q;
	ans[s]=0;
	q.push(EDGE(s,0));
	cnt[s]++;
	while(!q.empty()){
		EDGE e=q.front();
		q.pop();
		int pos=e.to;
		for(int i=0;i<graph[pos].size();i++){
			int to=graph[pos][i].to;
			int w=graph[pos][i].w;
			if(ans[to]>ans[pos]+w){
				ans[to]=ans[pos]+w;
				q.push(EDGE(to,ans[to]));
				cnt[to]++;
				if(cnt[to]>=n) return 0;
			}
		}
	}
	return 1;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a>>b>>y;
		graph[b].push_back(EDGE(a,y));
	}
	for(int i=1;i<=n;i++) graph[0].push_back(EDGE(i,0));
	if(SPFA(0)){
		for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
	}
	else cout<<"NO";
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值