差分约束 C++ 算法&例题

差分约束

差分约束 是一种特殊的 n 元一次不等式组,m 个约束条件,可以组成形如下的格式:
{ x 1 − x 1 ′ ≤ y 1 x 2 − x 2 ′ ≤ y 2 ⋯ x m − x m ′ ≤ y m \begin{cases} x_1-x_1^{'} \le y_1 \\ x_2-x_2^{'} \le y_2 \\ \cdots \\ x_m-x_m^{'} \le y_m \end{cases} x1x1y1x2x2y2xmxmym
我们的任务是需要求出一组解, x 1 = a 1 , x 2 = a 2 , ⋯   , x n = a n x_1=a_1,x_2=a_2,\cdots,x_n=a_n x1=a1,x2=a2,,xn=an

使得不等式组成立,否则为无解

注意到,每个式子都可以变形为 x i ≤ x i ′ + y i x_i\le x_i^{'}+y_i xixi+yi

那么就不难想到,图论中的 三角不等式 ,即为松弛操作

回忆——

if(dis[edge[i].to]>dis[t]+edge[i].w)
   	dis[edge[i].to]=dis[t]+edge[i].w;

虽说它这里是 >,不过也没有关系,不用考虑

既然知道了,那我们就按照图论的方法来解:

dis[0]=0 ,并且向着每一个节点连接一条权值为0的边,运用单源最短路,判断 负权环 ,若有负权环则为无解,否则依次输出 dis[i]

提到负权环,就不得不提判断负权环的大佬算法——SPFA!!!

对于那些不废 SPFA 的同学们,可以翻到我之前的博客区康康~~

好啦,看模板题——

luoguP5960 [模板]差分约束

AC Code:

#include<bits/stdc++.h>
using namespace std;
int n,m,cntedge;
const int MAXM=5e3+5,inf=65;
struct EDGE{
	int to,w,pre;
}edge[MAXM<<1];
int head[MAXM];
void add(int from,int to,int w)
{
	edge[++cntedge].to=to;
	edge[cntedge].w=w;
	edge[cntedge].pre=head[from];
	head[from]=cntedge;
	return;
}
bool vis[MAXM];
int u,v,w,t;
int dis[MAXM],cnt[MAXM];
queue<int> q;
bool spfa()
{
	q.push(0);
	cnt[0]++;
	vis[0]=true;
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		vis[t]=false;
		for(int i=head[t];i;i=edge[i].pre)
		{
			if(dis[edge[i].to]>dis[t]+edge[i].w)
			{
				dis[edge[i].to]=dis[t]+edge[i].w;
				if(vis[edge[i].to]) continue;
				q.push(edge[i].to);
				vis[edge[i].to]=true;
				if(++cnt[edge[i].to]>=n+1)
					return false;
			}
		}
	}
	return true;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) add(0,i,0);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		add(v,u,w);
	}
	memset(dis,inf,sizeof(dis));
	dis[0]=0;
	if(!spfa())
		printf("NO\n");
	else
	{
		for(int i=1;i<=n;i++)
			printf("%d ",dis[i]);
		printf("\n");
	}	
	return 0;
}

AC记录

  • 20
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值