问题 B: 图综合练习–拓扑排序
题目描述
已知有向图,顶点从0开始编号,求它的拓扑有序序列。
拓扑排序算法:给出有向图邻接矩阵
1.逐列扫描矩阵,找出入度为0且编号最小的顶点v
2.输出v,并标识v已访问
3.把矩阵第v行全清0
重复上述步骤,直到所有顶点输出为止
–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求
输入
第一行输入一个整数t,表示有t个有向图
第二行输入n,表示图有n个顶点
第三行起,输入n行整数,表示图对应的邻接矩阵
以此类推输入下一个图的顶点数和邻接矩阵
输出
每行输出一个图的拓扑有序序列
样例输入
2
5
0 1 0 1 1
0 0 1 0 0
0 0 0 0 1
0 0 1 0 0
0 0 0 0 0
7
0 0 0 0 0 0 0
1 0 1 1 0 0 0
1 0 0 0 0 0 0
1 0 1 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 0 0 1 0 1 0
样例输出
0 1 3 2 4
4 6 5 1 3 2 0
代码
#include <iostream>
#define N 10;
using namespace std;
class solution
{
public:
int graph[10][10];
int num;
bool visit[10];
void initial()
{
cin >> num;
for(int i=0;i<num;i++){
visit[i]=false;
for(int j=0;j<num;j++)
cin >> graph[i][j];
}
}
void toporder()
{
int v;
for(int k=0;k<num;k++){
for(int j=0;j<num;j++){
//找到入度为0的节点
if(visit[j])continue;
bool flag=false;
for(int i=0;i<num;i++){
if(graph[i][j]==1){
flag=false;
break;
}
flag=true;
}
if(flag){
v=j;break;}
}
visit[v]=true;
cout << v << ' ';
for(int j=0;j<num;j++)
graph[v][j]=0;
}
cout << endl;
}
};
int main()
{
int t;
cin >> t;
while(t--){
solution task;
task.initial();
task.toporder();
}
}
问题 D: 关键路径-STL版
题目描述
给定有向图无环的边信息,求每个顶点的最早开始时间、最迟开始时间。
// 参考代码
#include <iostream>
#include <vector>
#include <string>
#include <queue>
using namespace std;
class Vertex {
public:
int indexNo;
bool hasEnterQueue;
int early;
int later;
Vertex(int indexNo) {
this->indexNo = indexNo;
this->hasEnterQueue = false;
early = -1;
later = 0x7FFFF;
}
void updateEarly(int parentEarly, int edgeValue) {
int newEarly = parentEarly + edgeValue;
if (newEarly > this->early)
this->early = newEarly;
}
void updateLater(int childLater, int edgeValue) {
int newLater = childLater - edgeValue;
if (newLater < this->later)
this->later = newLater;
}
};
class Graph {
public:
vector<Vertex> vertexes;
vector<vector<int> > adjMat;
int n;
public:
void readVertexes() {
//TODO: 将顶点数读入成员变量n
//TODO: 从输入初始化vertexes数组
int i=0;
for(; i<n; ++i) {
Vertex v(i);
this->vertexes.push_back(v);
}
//为成员变量adjMat创建内存,赋初值
for(i=0; i<n; ++i) {
vector<int> row;
int j=0;
for(; j<n; ++j) {
//TODO: 将0增加到row最后
}
//TODO: 将row增加到adjMat最后
}
}
void readAdjMatrix() {
//read the adjacent info into this->adjMat
int edges;
cin >> edges;
int i=0;
int s, t, w; //s源顶点编号,t目的顶点编号,w边长
for(; i<edges; ++i) {
//TODO: 读入s,t,w,并将adjMat的第s行、第t列的值改为w.
}
}
void updateEarly(int parentNo, queue<int>& earlyQue) {
int parentEarly = vertexes[parentNo].early; //读入父结点early值
int j=0;
for(; j<n; ++j) {
int edgeValue = adjMat[parentNo][j];
if (edgeValue == 0) continue; //若父结点与结点j没有边相连,pass
Vertex& child = vertexes[j];
child.updateEarly(parentEarly, edgeValue); //更新子结点j的early信息
if(!child.hasEnterQueue) {
child.hasEnterQueue = true; //将子结点加入队列
earlyQue.push(j);
}
}
}
void updateLater(int childNo, queue<int>& laterQue) {
//TODO:
}
int getRoot() {
//获取入度为0的顶点
int j=0;
for(; j<n; ++j) {
int i=0;
for(; i<n && adjMat[i][j] == 0; ++i);
if (i>=n) return j; //j has not any in-edges.
}
return -1; //表示没找到
}
int getLeaf() {
//TODO: 获取出度为0的顶点
}
void printEarlyLater(bool isEarly) {
int i=0;
for(; i<n; ++i) {
Vertex& v = vertexes[i];
if (isEarly)
cout << v.early << " ";
else {
cout << v.later << " ";
}
}
cout << endl;
}
void findEarly() {
//执行关键路径算法,求每个顶点的最早开始时间。
int r = getRoot();
Vertex& root = vertexes[r];
root.hasEnterQueue = true;
root.early = 0;
queue<int> que;
que.push(r);
while(!que.empty()) {
int p = que.front();
que.pop();
updateEarly(p, que);
}
printEarlyLater(true);
}
void clearEnterQueue() {
int i=0;
for(; i<n; ++i) {
vertexes[i].hasEnterQueue = false;
}
}
void findLater() {
//TODO:调用clearEnterQueue,以清除每个顶点的hasEnterQueue=false
//执行关键路径算法,求每个顶点的最迟开始时间。
}
void main() {
readVertexes();
readAdjMatrix();
findEarly();
findLater();
}
};
int main() {
int t=1;
//cin >> t;
while (t--) {
Graph g;
g.main();
}
return 0;
}
输入
第一行图的顶点总数
第二行边的总数
第三行开始,每条边的时间长度,格式为源结点 目的结点 长度
输出
第一行:第个顶点的最早开始时间
第二行:每个顶点的最迟开始时间
样例输入
9
12
0 1 3
0 2 10
1 3 9
1 4 13
2 4 12
2 5 7
3 6 8
3 7 4
4 7 6
5 7 11
6 8 2
7 8 5
样例输出
0 3 10 12 22 17 20 28 33
0 9 10 23 22 17 31 28 33
代码
#include <iostream>
#include <vector>
#include <string>
#include <queue>
using namespace std;
class Vertex {
public:
int indexNo;
bool hasEnterQueue;
int early;
int later;
Vertex(int indexNo) {
this->indexNo = indexNo;
this->hasEnterQueue = false;
early = -1;
later = 0x7FFFF;
}
void updateEarly(int parentEarly, int edgeValue) {
int newEarly = parentEarly + edgeValue;
if (newEarly > this->early)
this->early = newEarly;
}
void updateLater(int childLater, int edgeValue) {
int newLater = childLater - edgeValue;
if (newLater < this->later)
this->later = newLater;
}
};
class Graph {
public:
vector<Vertex> vertexes;
vector<vector<int> > adjMat;
int n;//顶点数
public:
void readVertexes() {
//将顶点数读入成员变量n
cin >> n;
//从输入初始化vertexes数组
for(int i=0;i<n; ++i) {
Vertex v(i);
this->vertexes.push_back(v);
}
//为成员变量adjMat创建内存,赋初值
for(int i=0; i<n; ++i) {
vector<int> row;
int j=0;
for(; j<n; ++j) {
row.push_back(0);
//将0增加到row最后
}
adjMat.push_back(row);
//将row增加到adjMat最后
}
}
void readAdjMatrix() {
//read the adjacent info into this->adjMat
int edges;
cin >> edges;
int i=0;
int s, t, w; //s源顶点编号,t目的顶点编号,w边长
for(; i<edges; ++i) {
cin >> s >> t >> w;
adjMat[s][t]=w;
//读入s,t,w,并将adjMat的第s行、第t列的值改为w.
}
}
void updateEarly(int parentNo, queue<int>& earlyQue) {
int parentEarly = vertexes[parentNo].early; //读入父结点early值
for(int j=0; j<n; ++j) {
int edgeValue = adjMat[parentNo][j];
if (edgeValue == 0) continue; //若父结点与结点j没有边相连,pass
Vertex& child = vertexes[j];
child.updateEarly(parentEarly, edgeValue); //更新子结点j的early信息
if(!child.hasEnterQueue) {
child.hasEnterQueue = true; //将子结点加入队列
earlyQue.push(j);
}
}
}
void updateLater(int childNo, queue<int>& laterQue) {
//TODO:
}
int getRoot() {
//获取入度为0的顶点
for(int j=0; j<n; ++j)
for(int i=0; i<n && adjMat[i][j] == 0; ++i)
if (i>=n) return j; //j has not any in-edges.
return -1; //表示没找到
}
int getLeaf() {
//获取出度为0的顶点
for(int i=0;i<n;++i)
for(int j=0;j<n&&adjMat[i][j]==0;++j)
if(j>=n)return i;
return -1;
}
void printEarlyLater(bool isEarly) {
int i=0;
for(; i<n; ++i) {
Vertex& v = vertexes[i];
if (isEarly)
cout << v.early << " ";
else {
cout << v.later << " ";
}
}
cout << endl;
}
void findEarly() {
//执行关键路径算法,求每个顶点的最早开始时间。
int r = getRoot();
Vertex& root = vertexes[r];
root.hasEnterQueue = true;
root.early = 0;
queue<int> que;
que.push(r);
while(!que.empty()) {
int p = que.front();
que.pop();
updateEarly(p, que);
}
printEarlyLater(true);
}
void clearEnterQueue() {
int i=0;
for(; i<n; ++i) {
vertexes[i].hasEnterQueue = false;
}
}
// void findLater() {
// //TODO:调用clearEnterQueue,以清除每个顶点的hasEnterQueue=false
// //执行关键路径算法,求每个顶点的最迟开始时间。
// }
void findLater() //执行关键路径算法,求每个顶点的最玩开始时间。
{
clearEnterQueue();
int r = getLeaf();
Vertex &parent = vertexes[r];
parent.hasEnterQueue = true;
parent.later = parent.early;
queue<int> que;
que.push(r);
while(!que.empty())
{
int p = que.front();
que.pop();
updateLater(p,que);
}
printEarlyLater(false);
}
void main() {
readVertexes();
readAdjMatrix();
findEarly();
findLater();
}
};
int main() {
int t=1;
//cin >> t;
while (t--) {
Graph g;
g.main();
}
return 0;
}