差分约束
题目描述
给出一组包含 \(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;
}