【拓扑排序】工程

本文介绍了一种使用拓扑排序方法解决工程项目的依赖关系问题。通过子工程的完成时间和依赖关系,确定合理的施工顺序,以求得工程的最短完成时间。如果存在无法解决的依赖冲突,则输出-1。提供了一个包含输入输出样例的解题思路和程序实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工 程 工程


题目

张三是某工程公司的项目工程师。一天公司接下一项大型工程,该公司在大
型工程的施工前,先要把整个工程划分为若干个子工程,并把这些子工程编号为
1、2、„、N;这样划分之后,子工程之间就会有一些依赖关系,即一些子工程
必须在某些子工程完成之后才能施工,公司需要工程师张三计算整个工程最少的
完成时间。
对于上面问题,可以假设:
1、根据预算,每一个子工程都有一个完成时间
2、子工程之间的依赖关系是:部分子工程必须在一些子工程完成之后才开

3、只要满足子工程间的依赖关系,在任何时刻可以有任何多个子工程同时
在施工,也即同时施工的子工程个数不受限制

例如:有五个子工程的工程规划表:

序号完成时间子工程 1子工程 2子工程 3子工程 4子工程 5
子工程150000
子工程240000
子工程3120000
子工程471100
子工程521111

其中,表格中第 K + 1 K+1 K+1 J + 2 J+2 J+2 列的值为 0 0 0 表示“子工程 K K K”可以在“子工程 J J J
没完成前施工,为 1 1 1 表示“子工程 K K K”必须在“子工程 J J J”完成后才能施工
上述工程最快完成时间为 14 14 14
又例如,有五个子工程的工程规划表:

序号完成时间子工程 1子工程 2子工程 3子工程 4子工程 5
子工程150100
子工程240000
子工程3120010
子工程471100
子工程521111

上述的子工程划分不合理,因为无法安排子工程 1 , 3 , 4 1,3,4 134 的施工
现在对于给定的子工程规划情况,及每个子工程完成所需的时间,如果子工
程划分合理则求出完成整个工程最少要用的时间,如果子工程划分不合理,则输出 − 1 -1 1


输入

1 1 1 行为正整数 N N N,表示子工程的个数 ( N < = 200 ) (N<=200) N<=200 2 2 2 行为 N N N 个正整数
分别代表子工程 1 、 2 、 „ N 1、2、„N 12N 的完成时间
3 3 3 行到 N + 2 N+2 N+2 行,每行有 N − 1 N-1 N1 0 0 0 1 1 1,其中的第 K + 2 K+2 K+2 行的这些 0 0 0 1 1 1
分别表示“子工程 K K K”与子工程 1 、 2 、 „ 、 K − 1 、 K + 1 、 „ 、 N 1、2、„、K-1、K+1、„、N 12K1K+1N 的依赖关系 ( K = 1 、 2 、 „ 、 N ) (K=1、2、„、N) K=12N 每行数据之间均用空格分开

输出

如果子工程划分合理则输出完成整个工程最少要用的时间,如果子工程划分
不合理,则输出 − 1 -1 1


输入样例

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

project.in

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

project.out

-1

解题思路

就拓扑排序吧

程序如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;

queue<int>q;

int n, t[10001], f[10001], a[201][201], d[10001], ans;

void tuopu()
{
	while(!q.empty())
	{
		int p = q.front();
		q.pop();
		for(int i = 1; i <= n; ++i)
		{
			if(a[i][p])
			{
				d[i]--;
				t[i] = max(t[i], t[p] + f[i]);
				if(!d[i]) q.push(i);
			}
		}
	}
}

int main()
{
	freopen("project.in","r",stdin);
	freopen("project.out","w",stdout);
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i)
		scanf("%d",&f[i]);
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= n; ++j)
		{
			if(i != j)
			{
				scanf("%d",&a[i][j]);
				if(a[i][j]) d[i]++;
			}
		}
	}
	for(int i = 1; i <= n; ++i)
	{
		if(!d[i])
		{
			q.push(i);
			t[i] = f[i];
		}
	}
	tuopu();
	for(int i = 1; i <= n; ++i)
	{
		if(d[i])
		{
			printf("-1");
			return 0;
		}
	}
	for(int i = 1; i <= n; ++i)
		ans = max(ans, t[i]);
	printf("%d",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值