PTA_22_08_图8 _How Long Does It take
题目描述
Given the relations of all the activities of a project, you are supposed to find the earliest completion time of the project.
考虑到一个项目所有活动的关系,你应该找到项目最早的完成时间。
输入格式
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of activity check points (hence it is assumed that the check points are numbered from 0 to N−1), and M, the number of activities. Then M lines follow, each gives the description of an activity. For the i
-th activity, three non-negative numbers are given: S[i]
, E[i]
, and L[i]
, where S[i]
is the index of the starting check point, E[i]
of the ending check point, and L[i]
the lasting time of the activity. The numbers in a line are separated by a space.
每个输入文件包含一个测试用例。每种情况都从一行开始,该行包含两个正整数N(≤100),活动检查点的数量(因此假设检查点的编号从0到N−1) ,和M,活动的数量。接下来是M行,每行给出一个活动的描述。对于第i个活动,给出了三个非负数:S[i]、E[i]和L[i],其中S[i]是开始检查点的索引,E[i]是结束检查点,L[i]是活动的持续时间。一行中的数字用空格分隔。
9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
**************
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
输出样式
For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output “Impossible”.
对于每个测试用例,如果调度是可能的,则在一行中打印其最早完成时间;或者干脆输出“不可能”。
18
*************
Impossible
算法设计
根据陈越姥姥所说,本题是要用拓扑排序的思路进行求解
那么首先我们需要了解拓扑结构到底是什么,拓扑结构的算法很简单就是从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或则AOV网中不存在入度为0的顶点为止。
AOV网的概念则是,在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网。
对于拓扑结构往往采用邻接表的形式。
更完全的说,本题应该采用拓扑排序+关键路径两者相结合的算法
代码实现
#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
#define MAXSIZE 100
#define INFINITY 65535
struct Node
{
int N;
int M;
int A[MAXSIZE][MAXSIZE];
};
typedef struct Node* Pgraph;
int collect_time;//统计时间
void Creategraph(Pgraph graph)
{
int i, j;
int tmpstart, tmpend, tmptime;
cin >> graph->N >> graph->M;
//初始化边集
for ( i = 0; i < graph->N; i++)
{
for (j = 0; j < graph->N; j++)
{
graph->A[i][j] = INFINITY;
}
}
//将边集输入
for (i = 0; i < graph->M; i++)
{
cin >> tmpstart >> tmpend >> tmptime;
//因为是有相图
graph->A[tmpstart][tmpend] = tmptime;
}
}
int getmax(int arr[],Pgraph graph)
{
int max = 0;
for (int i = 0; i < graph->N; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
}
return max;
}
int topsort(Pgraph graph)
{
int v,i,j;
int cnt=0;//计算出队列元素的个数
int indrgree[MAXSIZE] = { 0 };//记录各点的入度
int EarliestTime[MAXSIZE] = { 0 };//记录最早完成的时间
queue<int>q;
//计算各结点的入度
for ( i = 0; i < graph->N; i++)
{
for (j = 0; j < graph->N; j++)
{
if (graph->A[i][j] != INFINITY)
{
indrgree[j]++;//对于有向边<i,j>累计记录终点为j的度
}
}
}
//入度为0的i入队
for (int i = 0; i < graph->N; i++)
{
if (indrgree[i] == 0)
q.push(i);
}
while (!q.empty())//当队列不空时
{
v = q.front();//v等于要出队列的元素
q.pop();
cnt++;
for (j = 0; j < graph->N; j++)
{
if(graph->A[v][j]!=INFINITY)//如果<v,j>存在有向边
{
if (EarliestTime[v] + graph->A[v][j] > EarliestTime[j])
{//如果v的最早完成时间+j所需时间>j的最早完成时间
EarliestTime[j] = EarliestTime[v] + graph->A[v][j];
//由关键路径的算法定义得出的
}
if (--indrgree[j] == 0)//去掉v后,j的入度如果为0,这个--是对每一个j都有效
{
q.push(j);
}
}
}
}
collect_time = getmax(EarliestTime, graph);
if (cnt != graph->N)
{
cout << "Impoosible";
return 0;
}
else
{
cout << collect_time;
}
}
int main()
{
Pgraph graph;
graph = (Pgraph)malloc(sizeof(struct Node));
Creategraph(graph);
topsort(graph);
}