关键子工程
Description
在大型工程的施工前, 我们把整个工程划分为若干个子工程, 并把这些子工程编号为 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 表示“子工程
上述工程最快完成时间为 14 天,其中子工程 1、
Input
第 1 行为
第 2 行为
第
其中的第 I+2 行的这些 0,
每行数据之间均用一个空格分开。
Output
如子工程划分不合理,则输出 −1;
如子工程划分合理,则用两行输出:
第 1 行为整个工程最少的完成时间。
第
Sample Input
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
Sample Output
14
1 3 4 5
Solution
最短时间:拓扑排序+DP。
关键子工程:
先找到结束时间最晚的一个或几个任务,然后再找到它们所依赖的任务中结束时间最晚的一个或几个任务……
Code
#include <iostream>
#include <cstdio>
#include <stack>
#include <queue>
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int head[210],nxt[100000],data[100000];
int head2[210],nxt2[100000],data2[100000];
int n,cnt,ans,tot;
int time[210];
int r[210],f[210];
stack<int>s;
priority_queue<int,vector<int>,greater<int> >q;
void add(int x,int y){
nxt[cnt]=head[x];data[cnt]=y;head[x]=cnt++;
nxt2[cnt-1]=head2[y];data2[cnt-1]=x;head2[y]=cnt-1;
}
void dfs(int now){
q.push(now);
for(int i=head2[now];i!=-1;i=nxt2[i])
if(f[now]==time[now]+f[data2[i]])
dfs(data2[i]);
}
int main(){
freopen("project.in","r",stdin);
freopen("project.out","w",stdout);
scanf("%d",&n);
memset(head,-1,sizeof head);
memset(head2,-1,sizeof head2);
for(int i=1;i<=n;i++)
scanf("%d",&time[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)if(i!=j){
int x;
scanf("%d",&x);
if(x==1){
add(j,i);
r[i]++;
}
}
for(int i=1;i<=n;i++)
if(r[i]==0){
s.push(i);
f[i]=time[i];
}
while(!s.empty()){
int now=s.top();
tot++;
s.pop();
for(int i=head[now];i!=-1;i=nxt[i]){
f[data[i]]=Max(f[data[i]],f[now]+time[data[i]]);
r[data[i]]--;
if(r[data[i]]==0)s.push(data[i]);
}
}
if(tot!=n){printf("-1\n");return 0;}
for(int i=1;i<=n;i++)ans=Max(ans,f[i]);
printf("%d\n",ans);
for(int i=1;i<=n;i++)
if(f[i]==ans)
dfs(i);
int pre=-1;
while(!q.empty()){
int now=q.top();
if(now!=pre)printf("%d ",now);
pre=now;
q.pop();
}
return 0;
}