目录
问题 A: 邻接矩阵存储的图,节点的出度和入度计算(附加代码模式)
问题 B: 算法7-12:有向无环图的拓扑排序
问题 C: 有向图是否存在环?
问题 D: 是否为有效的拓扑序列
问题 E: 案例6-2.6:最短工期
问题 F: 图-节点的最早发生时间
问题 G: 图-节点的最迟发生时间
问题 H: 图-边的最早发生时间
问题 I: 图-边的最迟发生时间
问题 J: 图-图的关键路径
仅作储存代码用。
问题 A: 邻接矩阵存储的图,节点的出度和入度计算(附加代码模式)
题目描述
可以用邻接矩阵的方式去存储一个图,要求计算这种方式下每个节点的入度和出度。
本题为附加代码模式,以下代码为自动附加在同学们提交的代码后面。在本题的提示中有代码框架,请同学们拷贝后,修改,再注释掉部分代码,最后提交。
// please comment the following code when you submit to OJ
int main(){
//freopen("/config/workspace/answer/test.in","r",stdin);
Graph g;
cin >> g.nodeNumber;
int inDegree[g.nodeNumber] = {0}, outDegree[g.nodeNumber] = {0};
for(int i=0;i<g.nodeNumber;i++){
for(int j=0;j<g.nodeNumber;j++){
cin >> g.adjMatrix[i][j];
}
}
CalculateDegree(g, inDegree, outDegree);
for(int i=0;i<g.nodeNumber;i++){
cout << inDegree[i] << " " << outDegree[i] << endl;
}
return 0;
}
输入格式
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。 以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个0或1,1表示第i个顶点和第j个顶点有直接连接,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。 注意输入的邻接矩阵不一定为对称矩阵,即输入的图一定是可能是有向图,也可能是无向图。
输出格式
对每一个节点,输出其入度和出度
输入样例 复制
4
0 1 0 1
1 0 0 0
0 0 0 1
1 0 1 0
输出样例 复制
2 2
1 1
1 1
2 2
数据范围与提示
代码框架如下:
#include <iostream>
#include <cstdio>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE];
};
// 计算每个节点的出度和入度
void CalculateDegree(const Graph& g, int inDegree[], int outDegree[]){
}
// please comment the following code when you submit to OJ
int main(){
// freopen("/config/workspace/answer/test.in","r",stdin);
Graph g;
cin >> g.nodeNumber;
int inDegree[g.nodeNumber] = {0}, outDegree[g.nodeNumber] = {0};
for(int i=0;i<g.nodeNumber;i++){
for(int j=0;j<g.nodeNumber;j++){
cin >> g.adjMatrix[i][j];
}
}
CalculateDegree(g, inDegree, outDegree);
for(int i=0;i<g.nodeNumber;i++){
cout << inDegree[i] << " " << outDegree[i] << endl;
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE];
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
// int main()
// {
// Graph g;
// cin>>g.nodeNumber;
// int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
// for(int i=0;i<g.nodeNumber;i++)
// {
// for(int j=0;j<g.nodeNumber;j++)
// cin>>g.adjMatrix[i][j];
// }
// CalculateDegree(g,inDegree,outDegree);
// for(int i=0;i<g.nodeNumber;i++)
// cout<<inDegree[i]<<" "<<outDegree[i]<<endl;
// return 0;
// }
问题 B: 算法7-12:有向无环图的拓扑排序
题目描述
由某个集合上的一个偏序得到该集合上的一个全序,这个操作被称为拓扑排序。偏序和全序的定义分别如下:
若集合X上的关系R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
设R是集合X上的偏序,如果对每个x,y∈X必有xRy或yRx,则称R是集合X上的全序关系。
由偏序定义得到拓扑有序的操作便是拓扑排序。
拓扑排序的流程如下:
1. 在有向图中选一个没有前驱的顶点并且输出之;
2. 从图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中存在环。
采用邻接表存储有向图,并通过栈来暂存所有入度为零的顶点,可以描述拓扑排序的算法如下:
在本题中,读入一个有向图的邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点序列。
输入格式
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。 以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个整数,如果为1,则表示第i个顶点有指向第j个顶点的有向边,0表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
输出格式
如果读入的有向图含有回路,请输出“ERROR”,不包括引号。 如果读入的有向图不含有回路,请按照题目描述中的算法依次输出图的拓扑有序序列,每个整数后输出一个空格。 请注意行尾输出换行。
输入样例 复制
4
0 1 0 0
0 0 1 0
0 0 0 0
0 0 1 0
输出样例 复制
3 0 1 2
数据范围与提示
*** 提示已隐藏,点击此处可显示 ***
收起提示[-]
在本题中,需要严格的按照题目描述中的算法进行拓扑排序,并在排序的过程中将顶点依次储存下来,直到最终能够判定有向图中不包含回路之后,才能够进行输出。 另外,为了避免重复检测入度为零的顶点,可以通过一个栈结构维护当前处理过程中入度为零的顶点。
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE];
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void mysort(Graph g,int indegree[])
{
stack<int>s;
int ans[g.nodeNumber];
int index=0;
int i=0;
for(i=0;i<g.nodeNumber;i++)
{
if(!indegree[i])
{
g.adjMatrix[i][i]=1;
s.push(i);
}
}
while(s.size()!=0)
{
ans[index++]=s.top();
i=s.top();
s.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=0&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
if(g.adjMatrix[j][j]==0&&indegree[j]==0)
{
g.adjMatrix[j][j]=1;
s.push(j);
}
}
}
if(index<g.nodeNumber)
cout<<"ERROR"<<endl;
else
{
for(int i=0;i<index;i++)
cout<<ans[i]<<" ";
}
}
int main()
{
Graph g;
cin>>g.nodeNumber;
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
cin>>g.adjMatrix[i][j];
}
CalculateDegree(g,inDegree,outDegree);
mysort(g,inDegree);
return 0;
}
问题 C: 有向图是否存在环?
题目描述
写程序判断有向图是否存在环。有向图的输入用n个二元组表示(u,v),表示从u到v有一条有向边,起点是u,终点是v。
输入格式
输入包括多组测试数据,每组测试数据首先是正整数n和m,表示有向图有n个节点(编号从1到n),m条有向边,接下来是m行,每行为两个正整数u和v,用空格隔开,表示从节点u到节点v有一条有向边,u和v都大于等于1且小于等于n
最后一行为0 0,表示测试数据结束
有向图的节点个数不超过100个,边的个数不超过1000
输出格式
如果该有向图存在环,输出YES,否则输出NO
输入样例 复制
11 10
1 2
2 3
4 3
5 4
6 5
3 9
10 9
9 11
7 8
8 11
2 2
1 2
2 1
3 3
1 2
2 3
3 1
0 0
输出样例 复制
NO
YES
YES
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE];
int vexNumber;
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void mysort(Graph g,int indegree[])
{
stack<int>s;
int ans[g.nodeNumber];
int index=0;
int i=0;
for(i=0;i<g.nodeNumber;i++)
{
if(!indegree[i])
{
g.adjMatrix[i][i]=1;
s.push(i);
}
}
while(s.size()!=0)
{
ans[index++]=s.top();
i=s.top();
s.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=0&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
if(g.adjMatrix[j][j]==0&&indegree[j]==0)
{
g.adjMatrix[j][j]=1;
s.push(j);
}
}
}
if(index<g.nodeNumber)
cout<<"ERROR"<<endl;
else
{
for(int i=0;i<index;i++)
cout<<ans[i]<<" ";
}
}
int main()
{
Graph g;
while(cin>>g.nodeNumber>>g.vexNumber)
{
if(g.nodeNumber==0&&g.vexNumber==0)
break;
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.vexNumber;i++)
{
int x,y;
cin>>x>>y;
g.adjMatrix[x][y]=1;
}
if(g.vexNumber>=g.nodeNumber)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
问题 D: 是否为有效的拓扑序列
题目描述
在一个有向无环图中,可能存在多种有效拓扑序列。以下图为例:
存在两种可行的拓扑序列:
0 1 2 3 4
0 2 1 3 4
本题会给出一个图,以及多个序列,你来判断每一个序列是否是该图的有效拓扑序列。
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
接下来为一个正整数o,表示接下来会出现的序列个数。
(o<1000)
再往后是o个序列,序列中的每个值用空格隔开。
输出格式
按行输出:o个序列中,每一个序列是否为图的有效拓扑序列。
是的话输出:YES
不是的话输出:NO
输入样例 复制
5 6
0 1
0 2
1 3
2 3
2 4
3 4
3
0 1 2 3 4
0 2 1 3 4
0 1 3 2 4
输出样例 复制
YES
YES
NO
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={0};
int vexNumber;
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
cin>>g.nodeNumber>>g.vexNumber;
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.vexNumber;i++)
{
int x,y;
cin>>x>>y;
g.adjMatrix[x][y]=1;
}
CalculateDegree(g,inDegree,outDegree);
int n;
cin>>n;
while(n--)
{
int temp;
queue<int>a;
for(int i=0;i<g.nodeNumber;i++)
{
cin>>temp;
a.push(temp);
}
judge(g,inDegree,a);
}
return 0;
}
问题 E: 案例6-2.6:最短工期
题目描述
一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。
输入格式
首先第一行给出两个正整数:项目里程碑的数量 N(≤100)和任务总数 M。这里的里程碑从 0 到 N−1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。
输出格式
如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。
输入样例 复制
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
输出样例 复制
18
数据范围与提示
如果有10万个里程碑顶点,但最后只有2个终点,则用扫描全部顶点的办法找最早结束时间比较大的那个顶点显然相当浪费。可以再加一个堆栈(或队列),将所有的终点入栈,则最后只需要检查这个栈里的顶点就可以了。试尝试这种思路。
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={-1};
int vexNumber;
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=-1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
int cnt=0;
cin>>g.nodeNumber>>g.vexNumber;
int dis[MAX_SIZE]={0};
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
g.adjMatrix[i][j]=-1;
}
for(int i=0;i<g.vexNumber;i++)
{
int x,y,time;
cin>>x>>y>>time;
g.adjMatrix[x][y]=time;
}
CalculateDegree(g,inDegree,outDegree);
stack<int>s;
for(int i=0;i<g.nodeNumber;i++)
{
if(inDegree[i]==0)
{
s.push(i);
dis[i]=0;
}
}
while(!s.empty())
{
int t=s.top();
s.pop();
cnt++;
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[t][i]!=-1)
{
inDegree[i]--;
if(inDegree[i]==0)
s.push(i);
if(dis[t]+g.adjMatrix[t][i]>dis[i])
dis[i]=dis[t]+g.adjMatrix[t][i];
}
}
}
if(cnt<g.nodeNumber)
cout<<"Impossible"<<endl;
else
{
int maxl=0;
for(int i=0;i<g.nodeNumber;i++)
{
if(dis[i]>maxl)
maxl=dis[i];
}
cout<<maxl<<endl;
}
return 0;
}
问题 F: 图-节点的最早发生时间
题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
最早发生时间:从前往后,前驱节点到当前节点所需时间,取最大值
本题要求:求出有向无环图中每一个节点的最早发生时间(示例图中每一个节点的最早发生时间以节点上方的黄色数字标出)
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
输出格式
按行输出有向无环图中每一个节点最早发生时间,按照节点的序号从小到大输出。
如样例中,0、1、2、3、4号节点的最早发生时间分别是0、3、3、7、11。
则按行输出0、3、3、7、11。
输入样例 复制
5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4
输出样例 复制
0
3
3
7
11
数据范围与提示
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={-1};
int vexNumber;
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=-1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
int cnt=0;
cin>>g.nodeNumber>>g.vexNumber;
int dis[MAX_SIZE]={0};
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
g.adjMatrix[i][j]=-1;
}
for(int i=0;i<g.vexNumber;i++)
{
int x,y,time;
cin>>x>>y>>time;
g.adjMatrix[x][y]=time;
}
CalculateDegree(g,inDegree,outDegree);
stack<int>s;
for(int i=0;i<g.nodeNumber;i++)
{
if(inDegree[i]==0)
{
s.push(i);
dis[i]=0;
}
}
while(!s.empty())
{
int t=s.top();
s.pop();
cnt++;
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[t][i]!=-1)
{
inDegree[i]--;
if(inDegree[i]==0)
s.push(i);
if(dis[t]+g.adjMatrix[t][i]>dis[i])
dis[i]=dis[t]+g.adjMatrix[t][i];
}
}
}
if(cnt<g.nodeNumber)
cout<<"Impossible"<<endl;
else
{
int maxl=0;
for(int i=0;i<g.nodeNumber;i++)
{
cout<<dis[i]<<endl;
}
}
return 0;
}
问题 G: 图-节点的最迟发生时间
题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
最迟发生时间:后序节点的最迟发生时间减去此边权值,取最小值
本题要求:通过逆拓扑序,求出有向无环图中每一个节点的最迟发生时间(示例图中每一个节点的最迟发生时间以节点上方的红色数字标出)
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
输出格式
按行输出有向无环图中每一个节点最迟发生时间,按照节点的序号从小到大输出。
如样例中,0、1、2、3、4号节点的最迟发生时间分别是0、5、3、7、11。
则按行输出0、5、3、7、11。
输入样例 复制
5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4
输出样例 复制
0
5
3
7
11
数据范围与提示
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={-1};
int vexNumber;
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=-1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
cin>>g.nodeNumber>>g.vexNumber;
int dis[MAX_SIZE]={0};
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
g.adjMatrix[i][j]=-1;
}
for(int i=0;i<g.vexNumber;i++)
{
int x,y,time;
cin>>x>>y>>time;
g.adjMatrix[x][y]=time;
}
CalculateDegree(g,inDegree,outDegree);
stack<int>s;
stack<int>s1;
stack<int>s2;
for(int i=0;i<g.nodeNumber;i++)
{
if(inDegree[i]==0)
{
s.push(i);
}
if(outDegree[i]==0)
{
s1.push(i);
s2.push(i);
}
}
while(!s.empty())
{
int t=s.top();
s.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[t][i]!=-1)
{
inDegree[i]--;
if(inDegree[i]==0)
s.push(i);
if(dis[t]+g.adjMatrix[t][i]>dis[i])
dis[i]=dis[t]+g.adjMatrix[t][i];
}
}
}
int outdegree[MAX_SIZE]={0};
for(int i=0;i<g.nodeNumber;i++)
outdegree[i]=outDegree[i];
while(!s1.empty())
{
int t=s1.top();
s1.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outDegree[i]--;
if(outDegree[i]==0)
s1.push(i);
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
while(!s2.empty())
{
int t=s2.top();
s2.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outdegree[i]--;
if(outdegree[i]==0)
s2.push(i);
if(dis[t]-g.adjMatrix[i][t]<dis[i])
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
for(int i=0;i<g.nodeNumber;i++)
cout<<dis[i]<<endl;
}
问题 H: 图-边的最早发生时间
题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
本题要求:求出有向无环图中每一个边的最早发生时间(示例图中每一个边的最早发生时间以边旁边的黄色数字标出)
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
输出格式
按行输出有向无环图中每一个边的最早发生时间,按照输入样例中边的输入次序输出。
如输入样例中,边的输入次序为:
0-->1
0-->2
1-->3
2-->3
2-->4
3-->4
则输出样例中,按行分别输出上述边的最早发生时间:0、0、3、3、3、7
输入样例 复制
5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4
输出样例 复制
0
0
3
3
3
7
数据范围与提示
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={-1};
int edgNumber;
};
struct edg{
int start;
int end;
int time;
}a[MAX_SIZE];
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=-1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
cin>>g.nodeNumber>>g.edgNumber;
int dis[MAX_SIZE]={0};
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
g.adjMatrix[i][j]=-1;
}
for(int i=0;i<g.edgNumber;i++)
{
int x,y,time;
cin>>x>>y>>time;
g.adjMatrix[x][y]=time;
a[i].start=x;
a[i].end=y;
a[i].time=time;
}
CalculateDegree(g,inDegree,outDegree);
stack<int>s;
stack<int>s1;
stack<int>s2;
for(int i=0;i<g.nodeNumber;i++)
{
if(inDegree[i]==0)
{
s.push(i);
}
if(outDegree[i]==0)
{
s1.push(i);
s2.push(i);
}
}
while(!s.empty())
{
int t=s.top();
s.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[t][i]!=-1)
{
inDegree[i]--;
if(inDegree[i]==0)
s.push(i);
if(dis[t]+g.adjMatrix[t][i]>dis[i])
dis[i]=dis[t]+g.adjMatrix[t][i];
}
}
}
// for(int i=0;i<g.nodeNumber;i++)
// cout<<dis[i]<<endl;
for(int i=0;i<g.edgNumber;i++)
{
a[i].time=dis[a[i].start];
}
int outdegree[MAX_SIZE]={0};
for(int i=0;i<g.nodeNumber;i++)
outdegree[i]=outDegree[i];
while(!s1.empty())
{
int t=s1.top();
s1.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outDegree[i]--;
if(outDegree[i]==0)
s1.push(i);
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
while(!s2.empty())
{
int t=s2.top();
s2.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outdegree[i]--;
if(outdegree[i]==0)
s2.push(i);
if(dis[t]-g.adjMatrix[i][t]<dis[i])
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
for(int i=0;i<g.edgNumber;i++)
cout<<a[i].time<<endl;
}
问题 I: 图-边的最迟发生时间
题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
本题要求:求出有向无环图中每一个边的最迟发生时间(示例图中每一个边的最迟发生时间以边旁边的红色数字标出)
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
输出格式
按行输出有向无环图中每一个边的最迟发生时间,按照输入样例中边的输入次序输出。
如输入样例中,边的输入次序为:
0-->1
0-->2
1-->3
2-->3
2-->4
3-->4
则输出样例中,按行分别输出上述边的最迟发生时间:2、0、5、3、7、7
输入样例 复制
5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4
输出样例 复制
2
0
5
3
7
7
数据范围与提示
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={-1};
int edgNumber;
};
struct edg{
int start;
int end;
int time;
}a[MAX_SIZE];
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=-1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
cin>>g.nodeNumber>>g.edgNumber;
int dis[MAX_SIZE]={0};
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
g.adjMatrix[i][j]=-1;
}
for(int i=0;i<g.edgNumber;i++)
{
int x,y,time;
cin>>x>>y>>time;
g.adjMatrix[x][y]=time;
a[i].start=x;
a[i].end=y;
a[i].time=time;
}
CalculateDegree(g,inDegree,outDegree);
stack<int>s;
stack<int>s1;
stack<int>s2;
for(int i=0;i<g.nodeNumber;i++)
{
if(inDegree[i]==0)
{
s.push(i);
}
if(outDegree[i]==0)
{
s1.push(i);
s2.push(i);
}
}
while(!s.empty())
{
int t=s.top();
s.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[t][i]!=-1)
{
inDegree[i]--;
if(inDegree[i]==0)
s.push(i);
if(dis[t]+g.adjMatrix[t][i]>dis[i])
dis[i]=dis[t]+g.adjMatrix[t][i];
}
}
}
// for(int i=0;i<g.nodeNumber;i++)
// cout<<dis[i]<<endl;
int outdegree[MAX_SIZE]={0};
for(int i=0;i<g.nodeNumber;i++)
outdegree[i]=outDegree[i];
while(!s1.empty())
{
int t=s1.top();
s1.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outDegree[i]--;
if(outDegree[i]==0)
s1.push(i);
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
while(!s2.empty())
{
int t=s2.top();
s2.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outdegree[i]--;
if(outdegree[i]==0)
s2.push(i);
if(dis[t]-g.adjMatrix[i][t]<dis[i])
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
for(int i=0;i<g.edgNumber;i++)
{
a[i].time=dis[a[i].end]-a[i].time;
}
for(int i=0;i<g.edgNumber;i++)
cout<<a[i].time<<endl;
}
问题 J: 图-图的关键路径
题目描述
下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。
本题要求:求出有向无环图中的每一个关键路径及其发生时间(示例图中每一个边的最早/最迟发生时间以边旁边的黄色/红色数字标出)
输入格式
第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。
接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。
(m<50,n<100)
输出格式
按行输出有向无环图中的所有关键路径及其发生时间,按照输入样例中边的输入次序输出。
如输入样例中,边的输入次序为:
0-->1
0-->2
1-->3
2-->3
2-->4
3-->4
则输出样例中,按行上述次序依次输出其中的关键路径及其发生时间:
0-->2:0
2-->3:3
3-->4:7
注意:输入数据中边的顺序不一定符合“行优先”规则。
输入样例 复制
5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4
输出样例 复制
0-->2:0
2-->3:3
3-->4:7
数据范围与提示
#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
struct Graph{
int nodeNumber;
int adjMatrix[MAX_SIZE][MAX_SIZE]={-1};
int edgNumber;
};
struct edg{
int start;
int end;
int maxtime;
int mintime;
}a[MAX_SIZE];
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[])
{
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]!=-1)
{
outDegree[i]++;
inDegree[j]++;
}
}
}
}
void judge(const Graph G,const int inDegree[], queue<int>a)
{
Graph g=G;
int indegree[g.nodeNumber];
for(int i=0;i<g.nodeNumber;i++)
indegree[i]=inDegree[i];
int i=0;
while(a.size()!=0)
{
i=a.front();
if(indegree[a.front()]!=0)
{
cout<<"NO"<<endl;
return ;
}
a.pop();
for(int j=0;j<g.nodeNumber;j++)
{
if(g.adjMatrix[i][j]==1&&i!=j)
{
g.adjMatrix[i][j]=0;
indegree[j]--;
}
}
}
cout<<"YES"<<endl;
return ;
}
int main()
{
Graph g;
cin>>g.nodeNumber>>g.edgNumber;
int dis[MAX_SIZE]={0};
int inDegree[g.nodeNumber]={0},outDegree[g.nodeNumber]={0};
for(int i=0;i<g.nodeNumber;i++)
{
for(int j=0;j<g.nodeNumber;j++)
g.adjMatrix[i][j]=-1;
}
for(int i=0;i<g.edgNumber;i++)
{
int x,y,time;
cin>>x>>y>>time;
g.adjMatrix[x][y]=time;
a[i].start=x;
a[i].end=y;
a[i].maxtime=time;
a[i].mintime=time;
}
CalculateDegree(g,inDegree,outDegree);
stack<int>s;
stack<int>s1;
stack<int>s2;
for(int i=0;i<g.nodeNumber;i++)
{
if(inDegree[i]==0)
{
s.push(i);
}
if(outDegree[i]==0)
{
s1.push(i);
s2.push(i);
}
}
while(!s.empty())
{
int t=s.top();
s.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[t][i]!=-1)
{
inDegree[i]--;
if(inDegree[i]==0)
s.push(i);
if(dis[t]+g.adjMatrix[t][i]>dis[i])
dis[i]=dis[t]+g.adjMatrix[t][i];
}
}
}
// for(int i=0;i<g.nodeNumber;i++)
// cout<<dis[i]<<endl;
for(int i=0;i<g.edgNumber;i++)
a[i].mintime=dis[a[i].start];
int outdegree[MAX_SIZE]={0};
for(int i=0;i<g.nodeNumber;i++)
outdegree[i]=outDegree[i];
while(!s1.empty())
{
int t=s1.top();
s1.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outDegree[i]--;
if(outDegree[i]==0)
s1.push(i);
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
while(!s2.empty())
{
int t=s2.top();
s2.pop();
for(int i=0;i<g.nodeNumber;i++)
{
if(g.adjMatrix[i][t]!=-1)
{
outdegree[i]--;
if(outdegree[i]==0)
s2.push(i);
if(dis[t]-g.adjMatrix[i][t]<dis[i])
dis[i]=dis[t]-g.adjMatrix[i][t];
}
}
}
for(int i=0;i<g.edgNumber;i++)
{
a[i].maxtime=dis[a[i].end]-a[i].maxtime;
}
for(int i=0;i<g.edgNumber;i++)
{
if(a[i].mintime==a[i].maxtime)
{
cout<<a[i].start<<"-->"<<a[i].end<<":"<<a[i].maxtime<<endl;
}
}
}