1.图的建立,初始化:
1)利用邻接矩阵
int n;
int G[N][N];
void init(){
memset(g,0,sizeof(g));//图的初始化
cin>>n;//读入数据个数
while(n--){
cin>>i>>j>>w;//读入两个顶点序号及权值
G[i][j]=w;//对于不带权的图,可令g[i][j]=1
G[j][i]=w;//无向图的对称性,若是有向图,没有此句
}
}
2)利用邻接表
又叫链式前向星,其实就是链表。邻接表的思想是,对于图中的每一个顶点,用一个数组来记录这个点和哪些点相连。
如果用邻接矩阵表示稀疏图就会浪费大量内存空间
,而用链接表,则是通过把顶点所能到的顶点的边保存在链表中来表示图。
#include<iostream>
#include<vector>
#define MAXN 1005
using namespace std;
struct edge{
int to,cost;//记录边的终点,边权
};
int n,m;
vector<edge> p[MAXN];
int v[MAXN][MAXN];
int main()
{
cin>>n>>m;//n个节点,m条边
for(int i=1;i<=n;i++)
{
int u,v,w;
cin>>u>>v>>w;
p[u].push_back((edge) {v,w});
}
for(int i=1;i<=n;i++)//遍历邻接表,把邻接表转换为邻接矩阵
{
for(int j=1;j<=n;j++)
{
v[i][p[i][j].to]=p[i][j].cost;
}
}
}
2.图的遍历
dfs:
//dfs遍历
//用栈维护,一般用递归实现
void solve(int x)
{
for(int i=0;i<p[x].size();i++)
{
if(!u[p[x][i]])
{
u[p[x][y]]=true;
solve(p[x][i]);
}
}
}
bfs:
//dfs遍历
//用栈维护,一般用递归实现
void solve(int x)
{
for(int i=0;i<p[x].size();i++)
{
if(!u[p[x][i]])
{
u[p[x][y]]=true;
solve(p[x][i]);
}
}
}
3.AOV 网与拓扑排序
AOV网:
日常生活中,一项大的工程可以看作是由若干个子工程组成的集合,这些子工程之间必定存在一定的先后顺序,即某些子工程必须在其他的一些子工程完成后才能开始。
我们用有向图来表现子工程之间的先后关系,子工程之间的先后关系为有向边,这种有向图称为“顶点活动网络”,即:AOV 网。
一个有向无环图称为无环图(Directed Acyclic Graph),简称 DAG 图,因此一个 AOV 网必定是一个有向无环图,即不带有回路。与 DAG 不同的是,AOV 的活动都表示在边上。
拓扑排序:
在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。
先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。
一直做改操作,直到所有的节点都被分离出来。
如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
queue<int>q;
vector<int>edge[n];
for(int i=0;i<n;i++) //n 节点的总数
if(in[i]==0) q.push(i); //将入度为0的点入队列
vector<int>ans; //ans 为拓扑序列
while(!q.empty())
{
int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
ans.push_back(p);
for(int i=0;i<edge[p].size();i++)
{
int y=edge[p][i];
in[y]--;
if(in[y]==0)
q.push(y);
}
}
if(ans.size()==n)
{
for(int i=0;i<ans.size();i++)
printf( "%d ",ans[i] );
printf("\n");
}
else printf("No Answer!\n"); // ans 中的长度与n不相等,就说明无拓扑序列
AOV网的判断:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#define N 10001
using namespace std;
int n,m;
int in[N];//节点入度
vector<int> G[N];//G[i]表示i节点所指向的所有其他点
bool judgeTopsort()//判断该图是否可拓扑排序
{
stack<int> S;
int cnt=0;//记录可拆解的点数目
for(int i=1;i<=n;i++)//枚举编号从1到n的点
if(in[i]==0)//入度为0,入栈
S.push(i);
while(!S.empty()) {
int x=S.top();//取栈顶元素
S.pop();
cnt++;//可拆点数+1
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
in[y]--;//入度减一
if(in[y]==0)//入度为0,出栈
S.push(y);
}
}
if(cnt==n)//AOV网点数等于图的点数,不存在环,可进行拓扑排序
return true;
else//AOV网点数等于图的点数,存在环,不可进行拓扑排序
return false;
}
int main()
{
while(scanf("%d%d",&n,&m)==2&&n)
{
memset(in,0,sizeof(in));
for(int i=1;i<=n;i++)
G[i].clear();
while(m--) {
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
in[y]++;
}
printf("%s\n",judgeTopsort()?"YES":"NO");
}
return 0;
}
#输出任意一条拓扑排序结果
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#define N 10001
using namespace std;
int n,m;
int in[N];//节点入度
int path[N];//存储路径
vector<int> G[N];//G[i]表示i节点所指向的所有其他点
void Topsort()//拓扑排序
{
stack<int> S;
int cnt=0;//记录可拆解的点数目
for(int i=1;i<=n;i++)//枚举编号从1到n的点
if(in[i]==0)//入度为0,入栈
S.push(i);
while(!S.empty()) {
int x=S.top();//取栈顶元素
S.pop();
path[++cnt]=x;//存储可拆点
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
in[y]--;//入度减一
if(in[y]==0)//入度为0,出栈
S.push(y);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)==2&&n)
{
memset(in,0,sizeof(in));
for(int i=1;i<=n;i++)
G[i].clear();
while(m--) {
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
in[y]++;
}
Topsort();
for(int i=1;i<=n;i++)
printf("%d ",path[i]);
printf("\n");
}
return 0;
}
#输出按字典序最小的拓扑排序结果//使用优先队列
//回头补一下优先队列的问题
ywm
//参考