DP+拓扑关键子工程
Posted Etta
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP+拓扑关键子工程相关的知识,希望对你有一定的参考价值。
【Description】
在大型过程的施工前,我们经常把整个工程分为若干个子工程,并把这些子工程编号为 1、2、…、N;这样划分之后,子工程之间就会有一些依赖关系,即一些子工程必须在 某些子工程完成之后才能施工。由于子工程之间有相互依赖关系,因此有两个任务需要 我们去完成:首先,我们需要根据每个子工程的完成时间计算整个工程最少的完成时间;
另一方面,由于一些不可预测的客观因素会使某些子工程延期,因此我们必须知道哪些
子工程的延期会影响整个工程的延期,我们把有这种特性的子工程称为关键子工程;因
此第二个任务就是找出所有的关键子工程,以便集中精力管理好这些子工程,尽量避免
这些子工程延期,达到用最快的速度完成整个工程。为了便于编程,现在我们假设: 2根据预算,每一个子工程都有一个完成时间。子工程之间的依赖关系是:部分子工程必须在一些子工程完成之后才开工。 只要满足子工程间的依赖关系,在任何时刻可以有任何多个子工程同时在施工,
也既同时施工的子工程个数不受限制。
整个工程的完成是指:所有子工程的完成。
例如,有5个子工程的工程规划表:
序号 | 完成时间 | 子工程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 | 0 |
其中,表格中第I+1行J+2列的值如为0表示“子工程I”可以在“子过程J”没完成前施工,为I表示“子工程I”必须在“子过程J”完成后才能施工。上述工程最快完成时间为 14天,其中子工程1、3、4、5为关键子工程。
【Input】
第3行到N+2行,每行有N-1个0或1。
其中的第I+2行的这些0,1,分别表示“子工程 I”与子工程1、2、…、I-1、I+1、…、N的依赖关系,(I=1,2,…,N)。每行数据之间 均用空格分开。
【Output】
如子过程划分合理,则用两行输出: 第1行为整个过程最好完成时间。
第2行为按有小到大顺序输出所有关键子过程的编号。
【Sample Input 1】
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 Input 2】
5
5 4 12 7 2
0 1 0 0
0 0 0 0
0 0 1 0
1 1 0 0
1 1 1 1
【Sample Output 1】
14
1 3 4 5
【Sample Output 2】
-1
【Analysis】
拓扑排序+DP
关键子过程即最晚完成时间与最早完成时间相同的子过程。
第一次使用stack,和priority_queue相似,但stack为先进后出,queue为先进先出,同有top(),pop(),push(),empty(),size()等关键字。
【Code】
1 #include<cstdio> 2 #include<queue> 3 #include<stack> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 8 const int sm = 200+10; 9 10 int n,tot,cnt,maxn,x,d; 11 int f[sm],g[sm],t[sm],h[sm],rd[sm],hh[sm],cd[sm]; 12 stack<int>s; 13 14 struct edge{ 15 int to,nxt; 16 }e[sm*2],ee[sm*2]; 17 18 void add(int f,int t) { 19 e[++tot].to=t; e[tot].nxt=h[f]; h[f]=tot; rd[t]++; 20 ee[tot].to=f; ee[tot].nxt=hh[t]; hh[t]=tot; cd[f]++; 21 } 22 23 int main() { 24 25 scanf("%d",&n); 26 for(int i=1;i<=n;++i)scanf("%d",&t[i]); 27 for(int i=1;i<=n;++i) 28 for(int j=1;j<=n;++j) { 29 if(i==j)continue; 30 scanf("%d",&x); 31 if(x)add(j,i); 32 } 33 34 for(int i=1;i<=n;++i) 35 if(!rd[i]) s.push(i),f[i]=t[i]; 36 37 while(!s.empty()) { 38 int now=s.top();s.pop(); 39 ++cnt; 40 for(int i=h[now];i;i=e[i].nxt) { 41 f[e[i].to]=max(f[e[i].to],f[now]+t[e[i].to]); 42 rd[e[i].to]--; 43 if(!rd[e[i].to])s.push(e[i].to); 44 } 45 } 46 47 if(cnt!=n){printf("-1\n");return 0;} 48 49 memset(g,0x3f,sizeof(g)); 50 for(int i=1;i<=n;++i) 51 if(cd[i]==0) { 52 s.push(i); 53 g[i]=maxn; 54 } 55 while(!s.empty()) { 56 int now=s.top(); 57 s.pop(); 58 for(int i=hh[now];i;i=ee[i].nxt) { 59 g[ee[i].to]=min(g[ee[i].to],g[now]-t[now]); 60 --cd[ee[i].to]; 61 if(!cd[ee[i].to])s.push(ee[i].to); 62 } 63 } 64 65 for(int i=1;i<=n;++i)maxn=max(maxn,f[i]); 66 printf("%d\n",maxn); 67 for(int i=1;i<=n;++i)if(f[i]==g[i])printf("%d ",i); 68 printf("\n"); 69 return 0; 70 }
以上是关于DP+拓扑关键子工程的主要内容,如果未能解决你的问题,请参考以下文章
DAG的运用:拓扑排序(AOV),关键路径(AOE)与dp的关系
[ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)
bzoj 1093: [ZJOI2007]最大半连通子图tarjan+拓扑排序+dp