图论-1讲课总结
2015-07-20 16:15
106 查看
图论-1主要讲了一下内容:
1.单源最短路径dij,多源最短路径floyd,负权图spfa
2.最小生成树 Prime,Kruskal
3.二分图,最小点覆盖,最大独立集
4.割点,割边。
下面就来详细写一下个部分内容,以免混淆。
一. 最短路径
1.首先是单源最短路径(无负权)的Dijskatra算法,该算法是基于贪心思想的,算法思想如下:
我们定义一个点集S,距离dis[]。点集S初始只有源点,dis[]初始化成源点到其他节点的距离。算法思想就是每次找到未加入S中的dis[]中的最小值,将其加入S中同时维护dis[]数组。就相当于把加入S点集中的点缩成一个点,就有相当于源点是的情况啦。这就是他的最有子结构与贪心策略。
Step1:初始化dis[]数组,源点加入S
Step2:查询不在S中且dis[]最小的
Step3:根据新加入的点更新dis
Step4:如果还有未加入S中的点,鸡血Step2.
下面给出邻接表的实现
2多源最短路径floyd
Floyd-Warshall算法的原理是动态规划。
设Di,j,k为从i到j的只以(1..k)集合中的节点为中间节点的最短路径的长度。
若最短路径经过点k,则Di,j,k = Di,k,k −
1 + Dk,j,k − 1;
若最短路径不经过点k,则Di,j,k = Di,j,k −
1。
因此,Di,j,k =
min(Di,k,k − 1 + Dk,j,k −
1,Di,j,k − 1)。
在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。(见下面的算法描述)
Floyd-Warshall算法的描述如下:
其中Di,j表示由点i到点j的代价,当Di,j为
∞ 表示两点之间没有任何连接。
下面是代码实现:
1.最小生成树的Prime算法
Prime算法也是基于贪心的思想,和dij很想,不过不同的是dis维护的是做过的路径长度最短,Prime算法维护的是加入的单个边的长度最短。
2最小生成树的Kruskal算法
Kruskal相当于贪心加上并查集的一种实现
对边的长度进行排序,然后依次检索每一条边,如果当前检索的边不在同一个连通分量里,就把这条边加入,将他们合并在一起,依次进行这个操作。
三.二分图
1.单源最短路径dij,多源最短路径floyd,负权图spfa
2.最小生成树 Prime,Kruskal
3.二分图,最小点覆盖,最大独立集
4.割点,割边。
下面就来详细写一下个部分内容,以免混淆。
一. 最短路径
1.首先是单源最短路径(无负权)的Dijskatra算法,该算法是基于贪心思想的,算法思想如下:
我们定义一个点集S,距离dis[]。点集S初始只有源点,dis[]初始化成源点到其他节点的距离。算法思想就是每次找到未加入S中的dis[]中的最小值,将其加入S中同时维护dis[]数组。就相当于把加入S点集中的点缩成一个点,就有相当于源点是的情况啦。这就是他的最有子结构与贪心策略。
Step1:初始化dis[]数组,源点加入S
Step2:查询不在S中且dis[]最小的
Step3:根据新加入的点更新dis
Step4:如果还有未加入S中的点,鸡血Step2.
下面给出邻接表的实现
#define INF 0xffffffff const int MAXN=1000; ///MAXN是节点的数目 typedef struct{ int to,cost; }node; vector<node> Grap[MAXN]; ///Grap[i]中存储的是i的邻接表。 int dis[MAXN]; bool vis[MAXN]; void Dij(int s){///源点是s memset(vis,0,sizeof(vis)); for(int i=0;i<MAXN;i++) dis[i]=INF; dis[s]=0; for(int i=0;i<MAXN;i++){ int Min=INF,pos; for(int j=0;j<MAXN;j++){ if(Min>dis[j]&&!vis[j]){ pos=j; Min=dis[j]; } } vis[pos]=1; for(int j=0;j<Grap[pos].size();j++){ int t=Grap[pos][i].to; dis[t]=min(dis[t],dis[pos]+Grap[pos][i].cost); } } }
2多源最短路径floyd
Floyd-Warshall算法的原理是动态规划。
设Di,j,k为从i到j的只以(1..k)集合中的节点为中间节点的最短路径的长度。
若最短路径经过点k,则Di,j,k = Di,k,k −
1 + Dk,j,k − 1;
若最短路径不经过点k,则Di,j,k = Di,j,k −
1。
因此,Di,j,k =
min(Di,k,k − 1 + Dk,j,k −
1,Di,j,k − 1)。
在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。(见下面的算法描述)
Floyd-Warshall算法的描述如下:
for k ← 1 to n do for i ← 1 to n do for j ← 1 to n do if (Di,k + Dk,j < Di,j) then Di,j ← Di,k + Dk,j;
其中Di,j表示由点i到点j的代价,当Di,j为
∞ 表示两点之间没有任何连接。
下面是代码实现:
for ( int k = 0 ; k < n ; k++ ) for ( int i = 0 ; i < n ; i++ ) for ( int j = 0 ; j < n ; j++ ) dis[i][j] = min ( dis[i][j] , dis[i][k] + dis[k][j] );3.对负权图的单源最短路径SPFA
int spfa_bfs(int s) { queue <int> q; memset(d,0x3f,sizeof(d)); d[s]=0; memset(c,0,sizeof(c)); memset(vis,0,sizeof(vis)); q.push(s); vis[s]=1; c[s]=1; //顶点入队vis要做标记,另外要统计顶点的入队次数 int OK=1; while(!q.empty()) { int x; x=q.front(); q.pop(); vis[x]=0; //队头元素出队,并且消除标记 for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表 { int y=v[k]; if( d[x]+w[k] < d[y]) { d[y]=d[x]+w[k]; //松弛 if(!vis[y]) //顶点y不在队内 { vis[y]=1; //标记 c[y]++; //统计次数 q.push(y); //入队 if(c[y]>NN) //超过入队次数上限,说明有负环 return OK=0; } } } } return OK; }二.最小生成树
1.最小生成树的Prime算法
Prime算法也是基于贪心的思想,和dij很想,不过不同的是dis维护的是做过的路径长度最短,Prime算法维护的是加入的单个边的长度最短。
2最小生成树的Kruskal算法
Kruskal相当于贪心加上并查集的一种实现
对边的长度进行排序,然后依次检索每一条边,如果当前检索的边不在同一个连通分量里,就把这条边加入,将他们合并在一起,依次进行这个操作。
三.二分图
相关文章推荐
- 一种排序
- [Oracle 10g会有的一个错误]ORA-00988: 口令缺失或无效
- 代码静态管理
- 第五节
- Android Studio导入eclipise快捷键
- Linux 简介
- bash shell学习之变量
- Linux下java使用Sigar的配置
- android自定义标题以及全屏设置
- 解决Eclipse里项目名有红叉,但是底下的每一个文件都没有红叉
- ZOJ 3795 - Grouping (强连通+dp)
- [原创]CACTI中自定义华为交换机CPU利用率 (图)
- Java并发编程的艺术
- log4j使用介绍
- 【欧拉函数】 TOJ 4125. Game
- PLSQL导入导出表的正确步骤
- 母函数入门
- 用Primefaces框架创建的报社管理系统
- 深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题
- AppDelegate.h中各个方法的使用