差分约束

题目描述

给出一组包含 \(m\) 个不等式,有 \(n\) 个未知数的形如:

\[\begin{cases} x_{c_1}-x_{c'_1}\leq y_1 \\x_{c_2}-x_{c'_2} \leq y_2 \\ \cdots\\ x_{c_m} - x_{c'_m}\leq y_m\end{cases} \]

的不等式组,求任意一组满足这个不等式组的解。

分析

考虑每个不等式类似最短路中的三角不等式,所以我们可以对该不等式组建图。

具体的,可将每个变量看成一个顶点,并设一个超级源点 \(x_0\),它连向每个顶点(除了自身)且边权为
\(0\),这时再对每一个不等式连一条边权为 \(k\) 的有向边 \(<i,j>\),此时用 \(x_i\) 表示超级源点到 \(j\) 的最短路,用 \(x_i\) 表示超级源点到 \(i\) 的最短路,由于有边 \(<i,j>\) 存在,从而有 \(x_j\le x_i+k\),即为原不等式的变形。

无论是最短路还是最长路都可以解决本题,我选择最长路。但是此时要考虑正环的情况。

在拓扑时我们记录一个 \(tot\),用 spfa 判环即可。

Code

点击查看代码
#include<bits/stdc++.h>

using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
int n,m;
int head[900100],len,dis[900100],tot[900100];
struct no
{
	int y,v,nxt;
}edge[900100];
void add(int a,int b,int c)
{
	edge[++len].y=b;
	edge[len].nxt=head[a];
	edge[len].v=c;
	head[a]=len;
}
bool vis[900100];   
queue<int> q;
bool bfs(int u)
{
    memset(vis, 0, sizeof vis); 
	memset(dis, -1, sizeof dis);
    memset(tot, 0, sizeof tot);
	vis[u]=1;
    dis[u]=0;
    tot[u]=1;
    q.push(u);
    while (q.size()) 
	{
        u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u];i; i =edge[i].nxt) 
		{
            int y=edge[i].y;
            int v=edge[i].v;
            if (dis[y]<dis[u]+v) 
			{
                dis[y]=dis[u]+v;
                if (!vis[y]) 
				{
                    q.push(y);
                    vis[y]=1;
                    if (++tot[y]>n+1) 
					return 1;
                }
            }
        }
    }
    return false;
		
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) add(0,i,0);
    for(int i=1;i<=m;i++)
    {
    	int a=read();int b=read();int c=read();
    	add(a,b,-c);
	}
	if(bfs(0)) cout<<"NO";
    else for(int i=1;i<=n;i++) cout<<dis[i]<<' ';
    return 0;
}

posted @ 2024-07-17 17:31  Redamancy_Lydic  阅读(7)  评论(0编辑  收藏  举报