在大型工程的施工前,我们把整个工程划分为若干个子工程,并把这些子工程编号为1、2、……、N;这样划分之后,子工程之间就会有一些依赖关系,即一些子工程必须在某些子工程完成之后才能施工。由于子工程之间有相互依赖关系,因此有两个任务需要我们去完成:首先,我们需要计算整个工程最少的完成时间;同时,由于一些不可预测的客观因素会使某些子工程延期,因此我们必须知道哪些子工程的延期会影响整个工程的延期,我们把有这种特征的子工程称为关键子工程,因此第二个任务就是找出所有的关键子工程,以便集中精力管理好这些子工程,尽量避免这些子工程延期,达到用最快的速度完成整个工程。为了便于编程,现在我们假设:
(1)根据预算,每一个子工程都有一个完成时间。
(2)子工程之间的依赖关系是:部分子工程必须在一些子工程完成之后才开工。
(3)只要满足子工程间的依赖关系,在任何时刻可以有任何多个子工程同时在施工,也既同时施工的子工程个数不受限制。
(4)整个工程的完成是指:所有子工程的完成。
例如,有五个子工程的工程规划表:
序号 |
完成时间 |
子工程1 |
子工程2 |
子工程3 |
子工程4 |
子工程5 |
子工程1 |
5 |
0 |
0 |
0 |
0 |
|
子工程2 |
4 |
0 |
0 |
0 |
0 |
|
子工程3 |
12 |
0 |
0 |
0 |
0 |
|
子工程4 |
7 |
1 |
1 |
0 |
0 |
|
子工程5 |
2 |
1 |
1 |
1 |
1 |
其中,表格中第I+1行J+2列的值如为0表示“子工程I”可以在“子工程J”没完成前施工,为1表示“子工程I”必须在“子工程J”完成后才能施工。上述工程最快完成时间为14天,其中子工程1、3、4、5为关键子工程。
又例如,有五个子工程的工程规划表:
序号 |
完成时间 |
子工程1 |
子工程2 |
子工程3 |
子工程4 |
子工程5 |
子工程1 |
5 |
0 |
1 |
0 |
0 |
|
子工程2 |
4 |
0 |
0 |
0 |
0 |
|
子工程3 |
12 |
0 |
0 |
1 |
0 |
|
子工程4 |
7 |
1 |
1 |
0 |
0 |
|
子工程5 |
2 |
1 |
1 |
1 |
1 |
上述的子工程划分不合理,因为无法安排子工程1,3,4的施工。
输入数据:
第1行为N,N是子工程的总个数,N≤200。
第2行为N个正整数,分别代表子工程1、2、……、N的完成时间。
第3行到N+2行,每行有N-1个0或1。其中的第I+2行的这些0,1,分别表示“子工程I”与子工程1、2、…、I-1、I+1、…N的依赖关系,(I=1、2、……、N)。每行数据之间均用一个空格分开。
输出数据:
如子工程划分不合理,则输出-1;
如子工程划分合理,则用两行输出:第1行为整个工程最少的完成时间。第2行为按由小到大顺序输出所有关键子工程的编号。
样例:
输入文件名:project. in
5
5 4 12 7 2
0 0 0 0
0 0 0 0
0 0 0 0
1 1 0 0
1 1 1 1
输出文件名:project. out
14
1 3 4 5
题意:
1),整个工程可划分为多个子工程,每个子工程有自己的时间,子工程之间会有依赖关系,(例如i在j之前完成)
2),整个工程完成是指所有子工程都完成
3),计算整个过程完成的最小时间
4),如果某些工程的时间影响整个过程完成的最小时间,这些工程被称为关键子工程。
找出所有的关键子工程。
拓扑排序,如果有环,则输出不等于输入,
根据拓扑排序的结果,
1、按f1[i]:=max{f1[j]+init[j]}(i是j的前驱)边境: f1[源点]:=init[源点]
此时所求的的是每一个工程的最晚开始时间
2、按f2[i]=min{f2[j]-init[j]}(i是j的后缀)边境:f2[汇点]:=f1[汇点]-init[汇点]
此时所求的是每一个工程的最早开始时间
3、如果一个工程的最早开始时间等于最晚开始时间,那这个工程为关键子工程
代码
var init,f1,f2:array[1..200]of longint;//f1[i]:最晚时间,f2[i]:最早时间
i,j,k,n:longint;
connected:array[1..200,1..200]of 0..1;
ru,chu:array[1..200]of integer;
used:array[1..200]of boolean;
can:boolean;
tuopu:array[1..200]of longint;
son,father:array[1..200,0..200]of longint;
function have:boolean;
var i:longint;
begin have:=false;
for i:=1 to n do
if (ru[i]=0)and(used[i])
then exit(true);
end;
begin readln(n);
for i:=1 to n do
read(init[i]);
fillchar(connected,sizeof(connected),0);
for i:=1 to n do
for j:=1 to n do
if i<>j
then begin read(connected[i,j]);
if connected[i,j]=1
then begin inc(chu[j]);
inc(father[j,0]);
father[j,father[j,0]]:=i;
inc(ru[i]);
inc(son[i,0]);
son[i,son[i,0]]:=j;
end;
end;
fillchar(used,sizeof(used),true);
k:=0;
while have do
begin for i:=1 to n do
if used[i]
then begin can:=false;
if ru[i]=0
then can:=true;
if can
then begin inc(k);
tuopu[k]:=i;
used[i]:=false;
for j:=1 to n do
if connected[j,i]=1
then dec(ru[j]);
end;
end;
end;
if k<>n
then begin writeln(‘-1‘);
halt;
end;
fillchar(ru,sizeof(ru),0);
for i:=1 to n do
for j:=1 to n do
if i<>j
then begin if connected[i,j]=1
then inc(ru[i]);
end;
k:=0;
for i:=1 to n do
if ru[i]=0
then inc(k);
for i:=1 to k do
f1[tuopu[i]]:=init[tuopu[i]];
for i:=k+1 to n do
for j:=1 to son[tuopu[i],0] do
if f1[tuopu[i]]<f1[son[tuopu[i],j]]+init[tuopu[i]]
then f1[tuopu[i]]:=f1[son[tuopu[i],j]]+init[tuopu[i]];
writeln(f1[tuopu[n]]);
for i:=1 to n do
f2[i]:=1000000000;
f2[tuopu[n]]:=f1[tuopu[n]];
for i:=n-1 downto 1 do
for j:=1 to father[tuopu[i],0] do
if f2[tuopu[i]]>f2[father[tuopu[i],j]]-init[father[tuopu[i],j]]
then f2[tuopu[i]]:=f2[father[tuopu[i],j]]-
init[father[tuopu[i],j]];
for i:=1 to n do
writeln(f2[i]);
for i:=1 to n do
if f1[i]=f2[i]
then write(i,‘ ‘);
end.