图论蛮好玩的呢 比起数论真是有趣多了
有空整理一下下
首先,图是个什么鬼东东呢
graph, 一堆点集,一堆边集,可以把各种事物抽象成点,事物之间的联系用边来表示,边上还可有权值,表示距离费用等
e.g. 把各个城市抽象成点,城市之间可以由高铁直达的称作有联系(边), 边上还可附加权值,俩城市间距离等
至于一些基本概念, 有向无向,是否成环,入度出度等就不多讲啦 基本概念理解就好
现在看看存图,看不同情况来选适合的存图方式
邻接矩阵---二维矩阵 a[ n ][ m ], 可用a[i][j]=1或0表示点i,j之间是否右边,缺点就是很占空间耶
邻接表---可以用链表呢(详见数据结构与算法,一些算法中提及的优化呵呵呵, 缺点就是修改查询麻烦
vector---归到邻接表啦,开个vector<ll>v[ N ], 点i,j有边,直接v[ i ].push_back(j)就好了 耶 操作也相对简单,某些题很适用
前向星---记录下每个起始点的第一条边,先按点同时按边遍历,需要排序, 详见代码
struct node { int s, e, w; }edge[MAXN];//边集 bool cmp(node a, node b) { if(a.s==b.s && a.e==b.e) return a.w<b.w; if(a.s==b.s) return a.e<b.e; return a.s<b.s; } int head[MAXN]; //存起点为i的第一条边的位置 int main() { int n, m; int i, j, k; while(cin>>m>>n) //m点 n条边 { for(i=0; i<n; i++) cin>>edge[i].s>>edge[i].e>>edge[i].w; sort(edge, edge+n, cmp); //排序以边的起点非递减序排 memset(head, -1, sizeof(head)); head[edge[0].s]=0; for(i=1; i<n; i++) if(edge[i].s!=edge[i-1].s) //存起点为i的第一条边的位置 head[edge[i].s]=i; for(i=1; i<=m; i++) //遍历各点 输出以该点为起始点的所有边 { for(k=head[i]; edge[k].s==i && k<n; k++) cout<<edge[k].s<<‘ ‘<<edge[k].e<<‘ ‘<<edge[k].w<<endl; } } }
链式前向星---不需排序 ,很巧妙, 详见代码
//链式前向星 /* edge[0].to = 2; edge[0].next = -1; head[1] = 0; edge[1].to = 3; edge[1].next = -1; head[2] = 1; edge[2].to = 4; edge[2],next = -1; head[3] = 2; edge[3].to = 3; edge[3].next = 0; head[1] = 3; edge[4].to = 1; edge[4].next = -1; head[4] = 4; edge[5].to = 5; edge[5].next = 3; head[1] = 5; edge[6].to = 5; edge[6].next = 4; head[4] = 6; */ #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<set> #include<string> using namespace std; const int INF=0x3f3f3f3f; typedef pair<int, int> p; typedef long long ll; #define fi first #define se second #define MAXN 10000+5 #define NIL -1 struct node { int next, to, w; //edge[i].to 存 第i条边 的终点 .next存与边i同起点的前一条边 }edge[MAXN]; int head[MAXN];//head[i] i为有边节点 head存该节点 边 的最大编号 存的是边 int cnt; void add(int u,int v,int w)//起点 终点 权值 { edge[cnt].w=w; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } int main() { int n, m; int i, j, k; int u, v, w; while(~scanf("%d%d", &n, &m)&& n && m) //n节点个数 m输入次数 一个节点可能有多条边 { memset(head, -1, sizeof(head)); cnt=0; for(i=0; i<m; i++) { scanf("%d%d%d", &u, &v, &w); add(u, v, w); } for(u = 1; u<=n; u++) for(i=head[u]; ~i; i=edge[i].next)//逆序遍历 i为边 printf("(%d %d)--> %d\n", u, edge[i].to, edge[i].w); } }
感觉用链式前向星比较顺手,看具体题目要求再选了
原文地址:https://www.cnblogs.com/op-z/p/10804068.html
时间: 2024-09-30 02:49:09