H y p e r l i n k Hyperlink Hyperlink
https://www.luogu.com.cn/problem/P5960
D e s c r i p t i o n Description Description
给定一个形如 x i − x j ≤ y x_i-x_j\leq y xi−xj≤y的 n n n元一次不等式组
求 x x x的一组整数解
S o l u t i o n Solution Solution
x i − x j ≤ k x_i-x_j\leq k xi−xj≤k
- 我们知道一个最短路数组 d d d,若有边 ( i , j ) (i,j) (i,j)它最后一定满足 d j ≤ d i + k d_j\leq d_i+k dj≤di+k
- 若有一个最长路数组 d d d,若有边 ( i , j ) (i,j) (i,j)它最后一定满足 d j ≥ d i + k d_j\geq d_i+k dj≥di+k
首先我们建边 ( 0 , i , 0 ) (0,i,0) (0,i,0)意义后面说
观察到与上述不等式十分相似,可以利用 s p f a spfa spfa判负环的思想
- 建立边 ( j , i , w ) (j,i,w) (j,i,w),跑最短路,最后可以得到 d d d最大的一组非正整数解
- 建立边 ( i , j , − w ) (i,j,-w) (i,j,−w),跑最长路,最后可以得到 d d d的一组最小正整数解
本代码采用的是后者
时间复杂度: O ( k m ) O(km) O(km),最坏情况 O ( n m ) O(nm) O(nm)
C o d e Code Code
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;int n,m,dis[5010],tot,l[5010],in[5010];
bool vis[5010];
struct node{int next,to,w;}e[20010];
inline void add(int u,int v,int w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
queue<int>q;
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline bool spfa(int s)
{
memset(dis,0xcf,sizeof(dis));
vis[s]=true;dis[s]=0;in[s]=1;
q.push(s);
while(q.size())
{
int u=q.front();q.pop();
for(register int i=l[u];i;i=e[i].next)
{
int v=e[i].to,w=e[i].w;
if(dis[v]<dis[u]+w)
{
dis[v]=dis[u]+w;
if(vis[v]==0) {vis[v]=1;q.push(v);in[v]++;if(in[v]>n+1) return true;}
}
}vis[u]=false;
}
return false;
}
signed main()
{
n=read();m=read();
for(register int i=1;i<=n;i++) add(0,i,0);
for(register int i=1,u,v,w;i<=m;i++) u=read(),v=read(),w=read(),add(u,v,-w);
if(spfa(0)) puts("NO");
else for(register int i=1;i<=n;i++) printf("%d ",dis[i]);
}