图论
(一)主要讲了图的基本概念,然后讲了图的几种形式,比如二分图,有向图,带权图,邻接矩阵,邻接表等等。
(二)图的存储
1.邻接表:用二维数字存储即可:int graph[num][unm]
优点:适合稠密图;编码非常简短;对边的存储,查询,更新等操作又快又简单,只需要一步就能访问和修改。
缺点:存储复杂度太高,大量的空间会被浪费;一般情况下不能存储重边;
2.邻接表:规模大的系数图一般用邻接表存储
优点:存储效率非常高,只需要与边数成正比的空间
缺点:编比邻接矩阵麻烦一些,访问和修改也慢一些
3.链式前向星:用静态数组模拟邻接表
优点:空间效率最高的一种方法,没有任何浪费,程序简单,能储存重边;
缺点:不方便做删除操作
(三)拓扑排序
拓扑排序的充要条件是他是一个有向无环图。有环图不能进行拓扑排序。
拓扑排序需要用到点的入度和出度的概念
出度:以点u为起点的边的数量称为u的出度。
入度:以点v为终点的边的数量称为的v入度。
拓扑排序无解的判断:如果队列已空,但是还有点未进入队列,那么这些点的入度都不是0,说明不是DAG,不存在拓扑排序。
题
hdu 1285
图这一块刚刚接触,所以对题目怎么解还是不了解,就先看看大佬的解法,熟悉熟悉模板
#include<bits/stdc++.h>
#define LL long long
#define inf 1<<30
using namespace std;
const int N=505;
int a,b,n,m,top;
struct node
{
int in; // 记录入度;
int out; // 记录出度;
}s[N];
bool Map[N][N]; // 用来标记a到b
bool vis[N]; // 用来标记是否已经Push输出了;
int st[N];
void Push(int i) // 存储最后排序结构;
{
st[++top]=i;
}
void TopSort()
{
int flag=1;
while(flag){
flag=0; // 用于判断是否全部Push;
for(int i=1;i<=n;i++){ // 遍历每一个点,
if(!vis[i]&&s[i].in==0){ // 从小到大找出入度为零的点,然后Push;
flag=1;
Push(i);
vis[i]=true;
for(int j=1;j<=n;j++){ // 因为i已经输出,所以所有有i到j入度的j的入度都要减一;
if(Map[i][j]) --s[j].in;
}
break; // 加一个这个才能够保证是按照从小到大输出;orz....
}
}
}
}
void Print() // 打印结果;
{
for(int i=1;i<top;i++) printf("%d ",st[i]);
printf("%d\n",st[top]);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
memset(Map,false,sizeof(Map));
memset(vis,false,sizeof(vis));
memset(s,0,sizeof(s));
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
if(!Map[a][b]){ // 数据可能有重复的边,一不小心就WA了;
s[a].out++;
s[b].in++;
}
Map[a][b]=true;
}
top=0;
TopSort();
Print();
}
return 0;
}
这周好像学的东西不是很多,dfs和bfs当初理解的还不是很透,所以拓扑排序有点看不大懂,下星期决定先把搜索这一块再复习一下。