题目链接工程规划 - 洛谷
差分约束本质上是给你一堆不等式求各个变量最小值和最大值,利用不等式建图,再利用SPFA求负环来判断有没有解
一般求变量最小值时求最长路
建图xi+c<=xj 由xi向xj连一条长度为c的边
如果a点到b点最长距离为w 即a+w<b
同理求变量最大值时求最短路
建图xi<=xj+c 由xj向xi连一条长度为c的边
如果a点到b点最短距离为w 即b<a+w
最后注意一点一定要找到一个形如xi<=c(常数)的不等式来求最值,这个时候可以根据题意建立超级原点 ,例如变量都大于0,那就建立一个0的原点连边,就可以保证每一个变量都能找到最值。
AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
int idx,h[2010],e[8010],ne[8010],w[8010];
int dist[2010],cnt[2010];
bool vi[2010];
int n,m;
void add(int a,int b,int c)
{
idx++;
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx;
}
bool spfa()
{
queue<int> q;
memset(dist,-0x3f,sizeof(dist));//初始化为负数,因为求最长路
dist[0]=0;
q.push(0);
vi[0]=true;
while(q.size())
{
int k=q.front();
q.pop();
vi[k]=false;
for(int i=h[k];i;i=ne[i])
{
int j=e[i];
if(dist[j]<w[i]+dist[k])//求最长路
{
dist[j]=w[i]+dist[k];
cnt[j]=cnt[k]+1;
if(cnt[j]>=n) return true;
if(!vi[j])
{
q.push(j);
vi[j]=true;
}
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,-c);
}
for(int i=1;i<=n;i++)
add(0,i,0);//因为工程开始时间都大于等于0,所以以0为超级原点,建立指向xi长度为0的边,即为0+0<xi
if(spfa()) printf("NO SOLUTION\n");//如果有负环无解
else
{
for(int i=1;i<=n;i++)
printf("%d\n",dist[i]);
}
return 0;
}
注意这题有多个解所以输出任意一种即可。(开始我还以为每个工程开始时间不可以一样,过不了样例,想复杂了,其实可以一样)。