九度OJ小结2
由于安排问题,距离上次小结时间已经过去很久。导致这次小结的内容很多。
本次小结涉及到主要内容如下所示:
- 基于并查集操作的最小生成树问题(prime算法或者kruskal算法);
- 最短路径问题(Floyd算法和dijkstra算法);
- 有向无环图问题(拓扑排序问题);
- 广度优先搜素BFS(Breadth First Search);
- 深度优先搜索DFS(Depth First Search);
- 递归问题;
- 回溯法;
- 递推算法;
- 最长递增子序列问题(一个数组LIS longest increasing subsequence);
- 最长公共公子序列问题(两个字符串 LCS longest common subsequence);
- 动态规划问题;
- 背包问题(0-1背包、0-1背包改进版、完全背包、多重背包) ;
- 字符串查找操作。
1. 最小生成树问题
对于最小生成树问题一般有两种求解方法:分别为prime算法和kruskal算法。
prime算法:
int prime(int cur) { int index = cur; int sum = 0; memset(visit, false, sizeof(visit)); visit[cur] = true; for(int i = 0; i < m; i ++){ dist[i] = graph[cur][i]; } for(int i = 1; i < m; i ++){ int mincost = INF; for(int j = 0; j < m; j ++){ if(!visit[j] && dist[j] < mincost){ mincost = dist[j]; index = j; } } visit[index] = true; sum += mincost; for(int j = 0; j < m; j ++){ if(!visit[j] && dist[j] > graph[index][j]){ dist[j] = graph[index][j]; } } } return sum; }
kruskal算法:
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <cmath> #define MAX_SIZE 1010 using namespace std; int n, m; int Tree[MAX_SIZE]; int findRoot(int x){//find the root of x if(Tree[x]==-1) return x; else{ int tmp = findRoot(Tree[x]);//continue the find Tree[x] = tmp;//change the root of x to tmp return tmp; } } int main(){ while(scanf("%d",&n)!=EOF && n!=0){//when n==0 and jump out of the loop scanf("%d",&m); for(int i = 1 ; i <= n ; i++)//init Tree[i] = -1; while(m--){ int a,b; scanf("%d%d",&a,&b); a = findRoot(a);//find the root of a b = findRoot(b);//find the root of b if(a!=b) Tree[a]=b;//merge those two sets to the same aggregates } int ans = 0 ; for(int i = 1 ; i <= n ; i++){ if(Tree[i]==-1) ans++;//calculate the total numbers of aggregates } printf("%d\n",ans-1); } return 0; }
2. 最短路径问题
对于最短路径问题一般使用两种算法Floyd算法和
Floyd算法:
void floyd() { for(int k = 0; k < n; k ++){ //作为循环中间点的k必须放在最外一层循环 for(int i = 0; i < n; i ++){ for(int j = 0; j < n; j ++){ if(dist[i][j] > dist[i][k] + dist[k][j]){ dist[i][j] = dist[i][k] + dist[k][j]; //dist[i][j]得出的是i到j的最短路径 } } } } }
Dijkstra算法
void dijkstra(int s) //s是起点 { memset(visit, false, sizeof(visit)); visit[s] = true; for(int i = 0; i < n; i ++){ dist[i] = graph[s][i]; } int index; for(int i = 1; i < n; i ++){ int mincost = INF; for(int j = 0; j < n; j ++){ if(!visit[j] && dist[j] < mincost){ mincost = dist[j]; index = j; } } visit[index] = true; for(int j = 0; j < n; j ++){ if(!visit[j] && dist[j] > dist[index] + graph[index][j]){ dist[j] = dist[index] + graph[index][j]; } } } }
最小生成树和最短路径的详细讲解以及算法实现代码见:http://www.cnblogs.com/zpfbuaa/p/6732997.html
3. 有向无环图问题
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
可参考题目:
题目链接:http://ac.jobdu.com/problem.php?pid=1448
题目链接:http://ac.jobdu.com/problem.php?pid=1449
题目链接:http://ac.jobdu.com/problem.php?pid=1450
拓扑排序操作:
-
首先,所有
有入度(即以该结点为弧头的弧的个数)的结点
不可能排在第一个。那么,我们选择一个入度为 0 的结点
,作为序列的第一个结点。当该结点被选为序列的第一个顶点后,我们将该点从图中删去,同时删去以该结点为弧尾的所有边,得到一个新图。 -
那么这个新图的拓扑序列即为原图的拓扑序列中除去第一个结点后剩余的序列。同样的,我们在新图上选择一个入度为0的结点,将其作为原图的第二个结点,并在新图中删去该点以及以该点为弧尾的边。这样我们就得到了一个新图,重复同样的方法,直到所有的结点和边都从原图中删去。
-
若在所有结点尚未被删去时即出现了找不到入度为0的结点的情况,则说明剩余的结点形成一个环路,拓扑排序失败,原图不存在拓扑序列。
4. 广度优先搜索BFS
使用队列的先进先出特性,对每一条路径组成的树进行全部遍历。BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。因此BFS适用于求解最优问题,而下面的深度优先搜索则适用于寻找问题是否有解。
可参考题目:
题目链接:http://ac.jobdu.com/problem.php?pid=1456
题目链接:http://ac.jobdu.com/problem.php?pid=1457
5. 深度优先搜索DFS
深度优先遍历图的方法是,从图中某顶点v出发:
一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
7. 回溯法
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
8. 最长递增子序列问题
常见的dp问题.
for(int i = 0 ; i < n ; i++){ for(int j = 0 ; j < i ; j++){ if(height[i]>height[j]){ l2r[i]=max(l2r[i],l2r[j]+1); } } }
可参考题目:
题目链接:http://ac.jobdu.com/problem.php?pid=1112
题目链接:http://ac.jobdu.com/problem.php?pid=1131
9. 最长公共公子序列问题
可参考题目:
题目链接:http://ac.jobdu.com/problem.php?pid=1042
10. 动态规划问题
推荐博客:http://www.cnblogs.com/wuyuegb2312/p/3281264.html
可参考题目:
题目链接:http://ac.jobdu.com/problem.php?pid=1452
题目链接:http://ac.jobdu.com/problem.php?pid=1453
11. 背包问题
背包九讲:http://www.cnblogs.com/zpfbuaa/p/4964317.html
0-1背包修改版:http://www.cnblogs.com/zpfbuaa/p/4966349.html
0-1背包再修改版:http://www.cnblogs.com/zpfbuaa/p/4966387.html
多重背包:http://www.cnblogs.com/zpfbuaa/p/4991895.html
完全背包:题目链接:http://ac.jobdu.com/problem.php?pid=1454
多重背包:题目链接:http://ac.jobdu.com/problem.php?pid=1455
12. 字符串操作
string转为char数组,str.c_str()
string中的替换:str.replace(startPos,replaceLegth,insertStr);
string中的查找:str.find(findSrtr,startPos) (返回值为第一次出现的下标)
string中的擦除:
(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
(2)erase(position);删除position处的一个字符(position是个string类型的迭代器)
(3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器)
其他操作转博客:http://blog.csdn.net/hanshileiai/article/details/6691755
作者: 伊甸一点
出处: http://www.cnblogs.com/zpfbuaa/
本文版权归作者伊甸一点所有,欢迎转载和商用(须保留此段声明),且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文链接 如有问题, 可邮件(zpflyfe@163.com)咨询.