关键子工程解题报告

关键子工程

【题目大意】

在大型工程的施工前,我们把整个工程划分为若干个子工程,并把这些子工程编号为1、2、……、N;这样划分之后,子工程之间就会有一些依赖关系,即一些子工程必须在某些子工程完成之后才能施工。由于子工程之间有相互依赖关系,因此有两个任务需要我们去完成:首先,我们需要计算整个工程最少的完成时间;同时,由于一些不可预测的客观因素会使某些子工程延期,因此我们必须知道哪些子工程的延期会影响整个工程的延期,我们把有这种特征的子工程称为关键子工程,因此第二个任务就是找出所有的关键子工程,以便集中精力管理好这些子工程,尽量避免这些子工程延期,达到用最快的速度完成整个工程。为了便于编程,现在我们假设:

(1)根据预算,每一个子工程都有一个完成时间。

(2)子工程之间的依赖关系是:部分子工程必须在一些子工程完成之后才开工。

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

(4)整个工程的完成是指:所有子工程的完成。

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




【输出格式】

如子工程划分不合理,则输出-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



先用拓扑排序判断是否合理,再分别求出一个子工程的最早最晚开工时间,判断是否有时间空隙,如果没有就是不能延期的关键子工程。


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=200+10;

int n,mi[maxn],ma[maxn],t[maxn],into[maxn],g[maxn][maxn],v[maxn];//mi(i):最早可以开始时间,ma(i):最晚必须开始时间
int ans=0;

void init()
{
	freopen("project.in","r",stdin);
	freopen("project.out","w",stdout);
}

void readdata()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&t[i]);
    memset(into,0,sizeof(into));
	memset(g,0,sizeof(g));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j) continue;
            scanf("%d",&g[j][i]);
            if(g[j][i]) into[i]++;
        }
    }
}

void tuopu() //循环每个子工程,假设这个子工程完成,然后改变相应的into[i]
{
	for(int i=1;i<=n;i++)
	{
		int j=1;
		while(j)
		{
			if(into[j]) j++;
			else 	break;
			if(j>n)
			{
				printf("-1\n");
				exit(0);
			}
		}
		into[j]=1000000;
		for(int i=1;i<=n;i++)
		{
			if(g[j][i]) into[i]--;
		}
	}
}

int dfsmin(int i)
{
    if(v[i]) return mi[i];
    v[i]=1;
    mi[i]=0;
    for(int j=1;j<=n;j++)//枚举前趋节点
    {
        if(g[j][i])
        {
            mi[i]=max(mi[i],dfsmin(j)+t[j]);
        }
    }
    return mi[i];
}

int dfsmax(int i)
{
    if(v[i]) return ma[i];
    v[i]=1;
    ma[i]=ans-t[i];
    for(int j=1;j<=n;j++)//枚举后继
    {
        if(g[i][j])
        {
            ma[i]=min(ma[i],dfsmax(j)-t[i]);
        }
    }
    return ma[i];
}

void work()
{
    tuopu();
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;i++)
    {
        int ti=dfsmin(i)+t[i];
        if (ans<ti) ans=ti;
    }
    printf("%d\n",ans);
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;i++)
    {
        if(!v[i])
            ma[i]=dfsmax(i);
    }
    for(int i=1;i<=n;i++)
    {
        if(mi[i]==ma[i])
            printf("%d ",i);
    }
}

int main()
{
	init();
	readdata();
	work();
	return 0;
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值