基础实验6-2.6 最短工期 (25分)
一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。
输入格式:
首先第一行给出两个正整数:项目里程碑的数量 N(≤100)和任务总数 M。这里的里程碑从 0 到 N−1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。
输出格式:
如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。
输入样例 1:
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
输出样例 1:
18
输入样例 2:
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
输出样例 2:
Impossible
这道题目我们需要用邻接表来建立
我们首先给出邻接表的定义
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 105
#define INFINITY -10005
typedef struct AdjNode *AdjList;
struct AdjNode
{
int index;
int weight;
AdjList next;
};
typedef struct HNode
{
AdjList FirstEdge;
}List[MAX];
typedef struct GNode *LGraph;
struct GNode
{
int Nv;
List head;
};
typedef struct ENode *Edge;
struct ENode
{
int v1,v2;
int weight;
};
然后是关于图和表的一些操作
void InsertEdge(LGraph G,Edge e)
{
AdjList NewNode;
NewNode=(AdjList)malloc(sizeof(struct AdjNode));
NewNode->index=e->v2;
NewNode->weight=e->weight;
NewNode->next=G->head[e->v1].FirstEdge;
G->head[e->v1].FirstEdge=NewNode;
}
LGraph CreateLGraph(int n,int m)
{
int v;
LGraph G=(LGraph)malloc(sizeof(struct GNode));
Edge E=(Edge)malloc(sizeof(struct ENode));
G->Nv=n;
for(v=0;v<n;v++)
{
G->head[v].FirstEdge=NULL;
}
for(v=0;v<m;v++)
{
scanf("%d%d%d",&E->v1,&E->v2,&E->weight);
InsertEdge(G,E);
}
return G;
}
最后就是这道题目的关键算法
拓扑排序
int TopSort(LGraph G)
{
int InDegree[MAX],Time[MAX],cnt=0,t=INFINITY;
int Queue[MAX],front,rear;//队列
int v;
AdjList w;
front=rear=0;
for(v=0;v<G->Nv;v++)
{
Time[v]=0;
InDegree[v]=0;
}
for(v=0;v<G->Nv;v++)//给各个点分配相应的度
{
for(w=G->head[v].FirstEdge;w;w=w->next)
{
++InDegree[w->index];
}
}
for(v=0;v<G->Nv;v++)//度为0的节点入队
{
if(!InDegree[v])Queue[++rear]=v;
}
while(front!=rear)
{
v=Queue[++front];//出队
cnt++;//计数
for(w=G->head[v].FirstEdge;w;w=w->next)
{
if(Time[v]+w->weight>Time[w->index])//相应的下标存的是前几个点权重的相加之和
Time[w->index]=Time[v]+w->weight;
if(--InDegree[w->index]==0)//度为0的节点再次入队
Queue[++rear]=w->index;
}
}
if(cnt==G->Nv)
{
for(v=0;v<cnt;v++)
if(t<Time[v])t=Time[v];//t等于最大的那个值
printf("%d\n",t);
}
else//cnt没计满,表示图中一定有回路
printf("Impossible\n");
}
主函数入口
int main() {
int n, m;
LGraph G;
scanf("%d%d", &n, &m);
G = CreateLGraph(n, m);
TopSort(G);
return 0;
}
话不多说总代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 105
#define INFINITY -10005
typedef struct AdjNode *AdjList;
struct AdjNode
{
int index;
int weight;
AdjList next;
};
typedef struct HNode
{
AdjList FirstEdge;
}List[MAX];
typedef struct GNode *LGraph;
struct GNode
{
int Nv;
List head;
};
typedef struct ENode *Edge;
struct ENode
{
int v1,v2;
int weight;
};
void InsertEdge(LGraph G,Edge e)
{
AdjList NewNode;
NewNode=(AdjList)malloc(sizeof(struct AdjNode));
NewNode->index=e->v2;
NewNode->weight=e->weight;
NewNode->next=G->head[e->v1].FirstEdge;
G->head[e->v1].FirstEdge=NewNode;
}
LGraph CreateLGraph(int n,int m)
{
int v;
LGraph G=(LGraph)malloc(sizeof(struct GNode));
Edge E=(Edge)malloc(sizeof(struct ENode));
G->Nv=n;
for(v=0;v<n;v++)
{
G->head[v].FirstEdge=NULL;
}
for(v=0;v<m;v++)
{
scanf("%d%d%d",&E->v1,&E->v2,&E->weight);
InsertEdge(G,E);
}
return G;
}
int TopSort(LGraph G)
{
int InDegree[MAX],Time[MAX],cnt=0,t=INFINITY;
int Queue[MAX],front,rear;
int v;
AdjList w;
front=rear=0;
for(v=0;v<G->Nv;v++)
{
Time[v]=0;
InDegree[v]=0;
}
for(v=0;v<G->Nv;v++)//给各个几点分配 度
{
for(w=G->head[v].FirstEdge;w;w=w->next)
{
++InDegree[w->index];
}
}
for(v=0;v<G->Nv;v++)//度为0的节点入队
{
if(!InDegree[v])Queue[++rear]=v;
}
while(front!=rear)
{
v=Queue[++front];//出队
cnt++;//计数
for(w=G->head[v].FirstEdge;w;w=w->next)
{
if(Time[v]+w->weight>Time[w->index])
Time[w->index]=Time[v]+w->weight;
if(--InDegree[w->index]==0)
Queue[++rear]=w->index;
}
}
if(cnt==G->Nv)
{
for(v=0;v<cnt;v++)
if(t<Time[v])t=Time[v];
printf("%d\n",t);
}
else
printf("Impossible\n");
}
int main()
{
int n,m;
LGraph G;
scanf("%d%d",&n,&m);
G=CreateLGraph(n,m);
TopSort(G);
return 0;
}