【问题描述】
造一幢大楼是一项艰巨的工程,它是由n个子任务构成的,给它们分别编号1,2,…,n(5≤n≤1000)。由于对一些任务的起始条件有着严格的限制,所以每个任务的起始时间T1,T2,…,Tn并不是很容易确定的(但这些起始时间都是非负整数,因为它们必须在整个工程开始后启动)。例如:挖掘完成后,紧接着就要打地基;但是混凝土浇筑完成后,却要等待一段时间再去掉模板。
这种要求就可以用M(5≤m≤5000)个不等式表示,不等式形如Ti-Tj≤b代表i和j的起始时间必须满足的条件。每个不等式的右边都是一个常数b,这些常数可能不相同,但是它们都在区间(-100,100)内。
你的任务就是写一个程序,给定像上面那样的不等式,找出一种可能的起始时间序列T1,T2,…,Tn,或者判断问题无解。对于有解的情况,要使最早进行的那个任务和整个工程的起始时间相同,也就是说,T1,T2,…,Tn中至少有一个为0。
【输入】
第一行是用空格隔开的两个正整数n和m,下面的m行每行有三个用空格隔开的整数i,j,b对应着不等式Ti-Tj≤b。
【输出】
如果有可行的方案,那么输出N行,每行都有一个非负整数且至少有一个为0,按顺序表示每个任务的起始时间。如果没有可行的方案,就输出信息“NO SOLUTION”。
【样例1】
work.in work.out
5 8 0
1 2 0 2
1 5 –1 5
2 5 1 4
3 1 5 1
4 1 4
4 3 –1
5 3 –1
5 4 –3
【样例2】
work.in work.out
5 5 NO SOLUTION
1 2 –3
1 5 –1
2 5 –1
5 1 –5
4 1 4
【算法分析】
本题是一类称为约束满足问题的典型问题,问题描述成n个子任务的起始时间Ti及它们之间在取值上的约束,求一种满足所有约束的取值方法。
将工程的n个子任务1,2,…,n作为一有向图G的n个顶点,顶点Vi(i=1,…,n)的关键值为子任务i的起始时间Ti,我们并不需要关心顶点之间的弧及其弧长,而是要确定顶点的关键值Ti的取值,满足所有的约束条件。本题的约束条件由m个不等式Ti-Tj≤b给出,这样的有向图称为约束图。
为了确定每一个Ti的值,先假设某一个子任务的起始时间为零,如设Tj=0,则其余子任务的起始时间Ti相对于T1可设置其起始时间为一区间[-maxt,maxt]。
下面分析不等式Ti-Tj≤b。此不等式可变形为如下两种形式:
(1)Ti≤Tj+b意味Ti的最大值为Tj+b;
(2)Tj≥Ti-b意味Tj的最大值为Ti-b;
因此,根据题中给出的m个不等式,逐步调整各个Ti的最小值和最大值。
设high[i]为Ti当前的最大值,low[i]为Ti当前的最小值。
high[j]为Tj当前的最大值,low[j]为Tj当前的最小值。
若high[i]-high[j]>b,则high[i]=high[j]+b(根据Ti≤Tj+b),
若low[i]-low[j]<b,则low[j]=low[i]-b(根据Ti≥Ti-b)。
以上的调整终止视下列两种情况而定:
(1)对所有的不等式Ti-Tj≤b,不再有high[i]或low[j]的调整;
(2)若存在high[i]<low[i]或high[j]<low[j]则表示不存在T1,T2,…,Tn能满足所有m个不等式Ti-Tj≤b,即问题无解。
/* <1>根据题意,假设一个开始任务,开始时间为0,其余的各项任务均 维护一个时间范围,即low[i]—high[i]。 由 Ti-Tj<=b 得:① Ti<=Tj+b,即 high[i]=high[j]+b; ② Tj>=Ti-b,即 low[j]=low[i]-b; <2>当high[i]-high[j]<=b 或者 low[i]-low[j]<=b 时,成立; 反之,则用以上①②式更新。 <3>当high[]<low[]时,没有可行方案, <4>当数据不再更新时,得出可行方案(满足数据非负,且至少有一个0)。 */ #include<cstdio> #include<iostream> #include<cstring> #define M 1010 #define N 5010 #define INF 10000 using namespace std; int high[M],low[M]; struct node { int x,y,v; };node a[N]; int main() { int n,m,x,y,v; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&v); a[i].x=x; a[i].y=y; a[i].v=v; } for(int i=2;i<=n;i++) { high[i]=INF; low[i]=-INF; } int flag=1,ff=0; while(flag) { flag=0; for(int i=1;i<=m;i++) { int x=a[i].x,y=a[i].y,b=a[i].v; if(high[x]-high[y]>b) { high[x]=high[y]+b; flag=1; } if(low[x]-low[y]>b) { low[y]=low[x]-b; flag=1; } if(high[x]<low[x]||high[y]<low[y]) { ff=1; flag=0; } } } if(ff)printf("NO SOLUTION"); else { int minn=INF; for(int i=1;i<=n;i++) minn=min(high[i],minn); for(int i=1;i<=n;i++) printf("%d ",high[i]-minn); } return 0; }