最短路&差分约束

博客介绍了Floyd、Dijkstra、SPFA三种算法,Floyd是多源最短路,Dijkstra用优先队列维护且不能有负权边,SPFA可用队列或DFS实现。还阐述了差分约束系统的定义和求解方法,可转化为图论的单源最短或最长路径问题,并给出了相关代码示例。

很久以前还有过一篇floyd和dijkstra的东西虽然写得丑也放上来吧

floyd

多源最短路,k要放在外面。

for(k=1;k<=n;k++)
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
dijkstra

用优先队列维护,不能有负权边。

memset(dist,0x3f,sizeof(dist));
dist[1]=0; q.push(PLI(0,1)); //priority_queue
while(!q.empty())
{
	int u=q.top().second;
	LL di=q.top().first;
	q.pop();
	if(di>dist[u]) continue;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i].first,w=G[u][i].second;
		if(dist[v]>dist[u]+w)
		{
			dist[v]=dist[u]+w;
			q.push(PLI(dist[v],v));
		}
	}
}
spfa

用队列存储可以松弛其他点的点,代码自行参考下面代码建完图之后的部分。

还可以用dfs来写,求负环会比较好。

void dfs(int u,double x)
{
	vis[u]=true;
	for(node *p=head[u];p!=NULL;p=p->nxt)
	{
		int v=p->v;
		double w=p->w-x;
		if(dist[v]>dist[u]+w)
		{
			if(vis[v]) { f=true; break; }
			dist[v]=dist[u]+w;
			dfs(v,x);
		}
	}
	vis[u]=false;
}

差分约束

1.定义

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

2.求解

求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。

观察不等式 a i − a j ≤ k a_i-a_j≤k aiajk,可以成为 a i ≤ k + a j a_i≤k+a_j aik+aj,长得就像求最短路时的松弛操作。所以对于每个不等式,可以建一条从j到i的有向边,边权为k。

如果符号不是≤,那就转化啊。
a i − a j ≥ k a_i-a_j \ge k aiajk可以转化为 a j − a i ≤ − k a_j-a_i \le -k ajaik
a i − a j &lt; k a_i-a_j \lt k aiaj<k可以转化为 a i − a j ≤ k − 1 a_i-a_j \le k-1 aiajk1
a i − a j = k a_i-a_j = k aiaj=k可以转化为 a i − a j ≤ k , a i − a j ≥ k a_i-a_j \le k,a_i-a_j \ge k aiajk,aiajk(然后再继续转化一下即可)。

如果要求最大值,那么转化为≤,跑最短路;如果要求最小值,那么转化为≥,跑最长路。

跑最短路时,如果发现负环,就说明题目给的信息矛盾,不等式组无解;
如果到达不了,就说明有变量没有被约束。

以下是bzoj1731的代码(就当一个写得比较丑的板子):

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
#define maxn 1005
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
struct node { int v,w; };
int n,ml,md,dist[maxn],cnt[maxn];
bool inq[maxn];
vector<node> G[maxn];
queue<int> q;
int main()
{
	scanf("%d%d%d",&n,&ml,&md);
	for(int i=2;i<=n;i++)
	{
		node p;
		p.v=i-1,p.w=0;
		G[i].push_back(p);
	}
	for(int i=1;i<=ml;i++)
	{
		int u; node p;
		scanf("%d%d%d",&u,&p.v,&p.w);
		G[u].push_back(p);
	}
	for(int i=1;i<=md;i++)
	{
		int u; node p;
		scanf("%d%d%d",&p.v,&u,&p.w);
		p.w=-p.w;
		G[u].push_back(p);
	}
	memset(dist,0x3f,sizeof(dist));
	dist[1]=0,inq[1]=true,cnt[1]=1;
	q.push(1);
	while(!q.empty())
	{
		int u=q.front();q.pop();
		inq[u]=false;
		for(int i=0;i<G[u].size();i++)
		{
			int v=G[u][i].v,d=G[u][i].w;
			if(dist[v]>dist[u]+d)
			{
				dist[v]=dist[u]+d;
				if(!inq[v])
				{
					cnt[v]++;
					q.push(v);inq[v]=true;
					if(cnt[v]>=n) { printf("-1\n"); return 0; }
				}
			}
		}
	}
	printf("%d\n",dist[n]==INF?-2:dist[n]);
}

题目:bzoj1731

### 差分约束系统短路径问题 差分约束系统是一种特殊的线性规划问题,可以通过将其转换为图论中的单源短路径问题来高效解。以下是具体的实现方式: #### 转化为图模型 差分约束系统的每个变量 \( x_i \) 对应于图中的一个节点。对于每一个约束条件 \( x_j - x_i \leq b_k \),可以在图中添加一条从节点 \( i \) 到节点 \( j \) 的有向边,其权重为 \( b_k \)[^2]。 为了确保所有节点都能被访问到,通常引入一个新的超级源点 \( s \),并从 \( s \) 向所有其他节点连一条权重为 0 的边[^3]。 #### 使用 Bellman-Ford 或 SPFA 算法 一旦构建好上述图结构,就可以通过运行 Bellman-Ford 算法或更高效的 SPFA 算法来计算从超级源点 \( s \) 出发到达各节点的短路径距离。这些距离值实际上对应着满足差分约束的一组可行解。 如果在执行过程中检测到了负权回路,则说明该差分约束系统无解;否则,得到的距离数组即为所需的结果[^5]。 下面是一个基于 Python 的简单实现示例: ```python from collections import deque, defaultdict def spfa(graph, n): dist = [float(&#39;inf&#39;)] * (n + 1) in_queue = [False] * (n + 1) queue = deque() # 初始化起点 queue.append(0) dist[0] = 0 in_queue[0] = True while queue: u = queue.popleft() in_queue[u] = False for v, w in graph[u]: if dist[v] &gt; dist[u] + w: dist[v] = dist[u] + w if not in_queue[v]: queue.append(v) in_queue[v] = True return dist # 构建图的例子 n = 5 # 假设有5个变量加上虚拟起点共6个节点 graph = defaultdict(list) # 添加一些约束条件作为边 constraints = [ (1, 2, 3), # 表示x2 - x1 &lt;= 3 (2, 3, 1), # 表示x3 - x2 &lt;= 1 (3, 4, 2), # 表示x4 - x3 &lt;= 2 ] for a, b, c in constraints: graph[a].append((b, c)) # 加入虚拟起点指向各个实际点的零权边 for node in range(1, n+1): graph[0].append((node, 0)) distances = spfa(graph, n) print(distances[1:]) # 输出除虚拟起点外的实际变量解 ``` 以上代码展示了如何利用 SPFA 来解决由若干差分不等式构成的约束系统,并获得相应的短路径解答。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值