2017.9.10-9.12
来源:互联网 发布:mac终端获取文件路径 编辑:程序博客网 时间:2024/06/02 01:02
=图论的学习
图论是数组结构中非常重要的一块
学习了图论之后 我渐渐的告别了模拟和简单的算法
开始学习更高深的东西
以下是我觉得这两天学习中的重点:
(1)邻接矩阵的读入:
Int const maxn=100Int a[maxn][maxn]memset(a,0, sizeof(a));Cin>>n;For (int i=0;i<n;i++) for(int j=0;j<n;j++) cin>>a[i][j];
还有一些变通的读入就不一一展开论述了
(2)邻接表的读入:
struct edge{ int y,v,next; //y表示这条边的终点编号,v是权值;}; //next表示同起点下条边的编号是多少edge e[maxm+10]; //边表。int linkk[maxn+10]; //起点表 link[i]表示由i出去的第一条边的下标是多少void insert(int ss,int ee,int vv)//ss为起点,ee为终点,vv为权值。{ e[++t].y=ee; e[t].v=vv; //t表示有t条边,是个全局变量。 e[t].next=linkk[ss]; linkk[ss]=t;}void init(){ scanf("%d %d %d",&n,&p,&m); for (int i=0;i<m;i++) { int xx,yy,zz; scanf("%d%d%d",&xx,&yy,&zz); insert(xx,yy,zz); insert(yy,xx,zz); //这里插入的是无向图,所以两条边都要插入。 } }
邻接矩阵只适合于20000个点左右的图 再打就会爆炸了
这时就要用到邻接表了
邻接表是链表中的一种 功能十分强大
在使用邻接表时有个很强大的
for (int i=linkk[k];i;i=e[i].next)
这句话在使用时经常出现
tips:
邻接矩阵:代码书写简单,找邻接点慢
采用二维数组的静态存储结构
一般点数|v|小于 等于5000的时候,用邻接矩阵。
邻接表:代码书写较复杂,找邻接点快
采用动态存储结构(指针或用数组模拟)
一般点数|v|大于等于5000,并且边得个数不是很多的时候,用邻接表,并且现在一般都是用数组来模拟。
数组模拟链表的速度会快一点,并且能避免一些错误。
(2)深度优先搜索 DFS
邻接矩阵:
Void dfs(int k);{ printf(“%d”,k); f[k]=true; for (int j=1;j<=n;j++) if ((!f[j])&& a[k][j]) dfs(j);}
邻接表的dfs :
void dfs(int k){ for (int i=linkk[k];i;i=e[i].next) if(!vis[e[i].y]) { vis[e[i].y]=1; dfs(e[i].y); }}
(3)求无向的连通分量:
sum=0; for (int i=1;i<-n;i++) if (! f[i]) { sum++; dfs(i); } cout<<sum;
(4)广度优先搜索(宽度优先搜索)BFS
Void bfs(int i);{ memset(q,0,sizeof(q)); int head=0,tail=1; q[1]=i; f[i]=true; while (head<tail) { k=q[++head]; cout>>k; for (int j=1;j<=n,j++) if (a[k][j] && !f[j]) { q[++tail]=j; f[j]=true; } } }
广度优先搜索用到了队列!
(5)图的传递闭包
传递闭包的算法:
判断结点 i 到 j是否有路径
1、结点 i 到 j 有边则有路径。
2、 i 到 j 之间没有边:
如果存在另外的一个结点k,满足:i到k有路径,k到j有路径,则i到j有路径。否则i到j没有路径。
can[ i ][ j ]=true:i到j有边; can[ i ][j ]= false:无边。
则:can[ i ][ j ]=can[ i][ j] || ( can[ i ][ k ] && can[ k ][ j ])
for (int i=1;i<=n;i++) can[i,i]:=true; for (int k=1;k<=n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) can[i][j] ||= (can[i][k] && can[k][j]);
学了一些简单(嘿嘿嘿)的图论概念后
就可以来求一些最短距离问题了
这边就有几个大佬的算法
1、图中每对顶点(任意两点)之间的最短路径
(弗洛伊德算法:floyed)。
2、图中一个顶点到其他顶点的最短路径
(迪杰斯特拉算法:dijkstra)。
还有什么bellman-Ford SPFA
(1)floyed算法:
for (int k=1;k<=n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (d[i][k]+d[k][j]<d[i][j] ) d[i][j]=d[i][k]+d[k][j]
初始化条件:
D[ i][ i ]=0 //自己到自己为0;对角线为0;
D[i][j]=边权,i与j有直接相连的边
D[i][j]= +∞ ,i与j无直接相连的边。
// 一般设为: memset 10 即可;
(2)Dijkstra算法
上照片:
void dijkstra(int st){ for (int i=1;i<=n;i++) dis[i]=a[st,i]; memset(f,false,sizeof(f)); f[st]=true; dis[st]=0; for (int i=1;i<n;i++) { int min=1000000000, k=0; for (int j=1;j<=n;j++) if (!f[j] && (dis[j]<min)) min=dis[j],k=j; if (k==0) return; //已经找不到了。 f[k]=true; //把k加入集合1; for (int j=1;j<=n;j++) //三角形迭代,更新最短距离 if (!f[j] && (dis[k]+a[k][j]<dis[j])) dis[j]=dis[k]+a[k][j]; }}Cout<<dis[en]
时间:O(n2)
注意!!!!
Floyed: 可以有负权,无负权回路。O(n^3)
Dijkstra: 不能有负权。O(n^2)
最短路径—–Bellman-ford算法
如果边有负权的话,Dijkstra算法是错误的。这里需要不断迭代地做“松驰”,直到无“松驰”为止。
算法描述3:
SP_Bellman(G, s)
(1)初始化每点到s点的最短距离为∞
(2)取所有边(x,y),看x能否对y松驰。
(3)如果没有任何松驰,则结束break。
(4)如果松驰次数
SP_Bellman(G, s) //求单源s到其它点的最短距离 for i=1 to n do dis[i] ∞ // 初始化每点到s距离dis[s] 0 //将dis[s]设为0for i=1 to n do //最多迭代n rel=false; //是否有松驰标志 for 每条边(x,y) //取图的每一条边 if( dis[x]+len[x][y]<dis[y]) //不满足三角形性质 dis[y]=dis[x]+len[x][y]; //松驰dis[y] rel=true; if rel = false return 0; //没有一次松驰,则结束return -1; //迭代了n次,有负圈
SPFA在形式上和宽度优先搜索非常类似,不同的是宽度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身会再次被改进,于是再次用来改进其它的点,这样反复迭代下去。
图的最小生成树
普里姆算法(prim)
克鲁斯卡尔(kruskal)
生成树:一个|V|个点的图,取其中|V|-1条边,并连接所有的顶点,则组成原图的一个生成树。
属性:|v|-1条边、连通、无环。
最小生成树:加权图的最小生成树是一棵生成树,其所有边的权值之和不会大于其它任何生成树。
简单讲:找出连接所有点的最低成本路线
最小生成树(MST)—–算法原理
(1)剪切属性:在图中,剪切将顶点划分成两个不相交集合。交叉边为这些顶点在两个不同集合的边。对于任何一个剪切,各条最小的交叉边都属于某个MST,且每个MST中都包含一条最小交叉边。
(2)最小边原则:图中权值最小的边(如果唯一的话)一定在最小生成树上。
(3)唯一性:一棵生成树上,如果各边的权都不相同,则最小生成树是唯一的。反之不然。
参考资料:老师的ppt
- 2017.9.10-9.12
- 2017.9.10
- 2017.9.10 学习心得
- 2017.9.10更新日志
- 2017.9.9-2017.9.10---训练赛
- 9.12
- 9.12
- 9.12
- 9.12
- 第一周总结----2017.9.10
- 2017.9.10 ricehub 思考记录
- 2017.9.10 机房模拟赛
- 2017.9.10 土地购买 思考记录
- 2017.9.10 序列操作 思考记录
- 2017.9.10 连续攻击游戏 思考记录
- 群赛10总结----2017.9.16(又是奇怪题目)
- 习题9.12
- 9.12--9.13
- 通过dbcp连接池连接数据库的操作
- 缓存微信接口凭据access_token:初步认识ServletContext
- Spring AOP中pointcut expression表达式解析及匹配多个条件
- 一、Ubuntu U盘系统安装以及初步设置
- 数据结构之二分查找树
- 2017.9.10-9.12
- 反射机制
- Linux 字体颜色设置
- 如何用指针遍历图像中的每一个像素
- MT6580 Video Feature Introduction
- 有序表查询之二:java实现插值查询
- 九度 题目1144:Freckles
- 656
- html2canvas根据DOM元素样式实现网页截图