图论,算法

文章介绍了如何使用邻接矩阵和邻接表来建立图,并展示了图的深度优先搜索(DFS)和广度优先搜索(BFS)的实现。此外,还讨论了顶点活动网络(AOV网)的概念以及拓扑排序的算法,包括判断有向无环图(DAG)是否可进行拓扑排序的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

#输出按字典序最小的拓扑排序结果//使用优先队列

 //回头补一下优先队列的问题

http://t.csdn.cn/rf92S

ywm

//参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值