常规笔试算法 上部 练习版(练习编程必做)
来源:互联网 发布:电脑恢复手机数据 编辑:程序博客网 时间:2024/06/05 15:58
为了有效地练习,你需要购买胡凡编写的《算法笔记》两本书,
简单说明下理由,首先胡凡学长为我校浙大的考研老前辈了,其当年专门精研PAT考试习题,
其次这本书对常规考点都做了详细整理,对习题也按照考点分类划为章节,你需要严格按照分类来专门定点练习突破,
最后这本书对一些Online Judge测试点都作了详细注解,都是一些你不可不知、不可不会的关键点,
当然如果你自我感觉良好,觉得一己之力都可以解决很多应试问题,那你自便吧祝你上天成功。
这里说明下2015年校招的笔试情况,据我所做的笔试看,基本只有少数几家大公司(记得有腾讯)用的是自己的考试平台,
多数公司用的都是牛客网的笔试题,其中编程部分的考点都可以在PAT考试中找到,所谓PAT考试,
PAT就是浙大这些年不断发展的一个编程能力考试,人人都可以免费注册练习,PAT的题型和难度与现行的笔试几乎相同,
牛客网的很多题目很难找到题解,而PAT的每道题你都可以找到很多版本的详解,
因此非常建议你用《算法笔记》和PAT历年真题来练习应试编程。
下述的图论算法模板你可以首先作为样例学习,然后参见下一篇博客《常规笔试算法 下部 应试版(笔试编程必考)》所作的精简归纳。
#include <cstdio>#include <vector>#include <queue>#include <map>#include <algorithm>using namespace std;#define NVTX_MAX 100struct Vtx { int num;};struct Edg { int vtx; int adj; int len; friend bool operator<(Edg edg1, Edg edg2) { return edg1.len > edg2.len; }};// edgs[sv][di]是后继图,每行// 不变的数据结构,每个测例都要调用InitG()int nvtx, nedg;int svtx, dvtx;Vtx vtxs[NVTX_MAX]; // 仅当点有权值才需要vector<Edg> edgs[NVTX_MAX];map<char,int> n2vs; // 仅当点是字母才需要map<int,char> v2ns;// 可变的数据结构,每个算法都要调用InitX()// vsts[]是遍历状态(0,1,2),控制点的访问次数// dfps[]是在路径中(true,false),控制深搜不形成环路int vsts[NVTX_MAX];bool dfps[NVTX_MAX]; // 仅当在深搜递归中点可多次访问才需要int idegs[NVTX_MAX]; // 仅当调用Topo()才需要vector<int> topo0;int nums[NVTX_MAX]; // 仅当点有权值才需要int dsts[NVTX_MAX];vector<Edg> prvs[NVTX_MAX]; // 仅当多条路径才需要vector<Edg> mst0; // 仅当调用用Prim()、Kruskal()才需要// 特别注意某些垃圾题目(POJ 1258)没有给出测例个数,必须用scanf()返值判断结束bool ScanG() { // 读取邻接列表图 if (scanf("%d %d %d %d", &nvtx, &nedg, &svtx, &dvtx) == EOF) { return false; } // 读取点的权值 /* for (int i = 0; i < nvtx; i += 1) { Vtx vtx; scanf("%d", &vtx.num); vtxs[i] = vtx; } */ for (int i = 0; i < nedg; i += 1) { Edg edg; scanf("%d %d %d", &edg.vtx, &edg.adj, &edg.len); edgs[edg.vtx].push_back(edg); // 无向图加两边 /* swap(edg.vtx, edg.adj); edgs[edg.vtx].push_back(edg); */ } return true; // 读取邻接矩阵图 /* if (scanf("%d", &nvtx) == EOF) { return false; } for (int i = 0; i < nvtx; i += 1) { for (int j = 0; j < nvtx; j += 1) { Edg edg; edg.vtx = i; edg.adj = j; scanf("%d", &edg.len); edgs[i].push_back(edg); } } return true; */}// 特别注意某些垃圾题目(POJ 1270)没有给出点的个数,必须重置清零,注意顺序与定义相反void InitG() { n2vs.clear(); v2ns.clear(); for (int v = 0; v < nvtx; v += 1) { edgs[v].clear(); } nvtx = 0; nedg = 0; // 特别注意先清空边集后清零边数 svtx = 0; dvtx = 0;}void InitDeg() { for (int v = 0; v < nvtx; v += 1) { idegs[v] = 0; } for (int v = 0; v < nvtx; v += 1) { for (int i = 0; i < edgs[v].size(); i += 1) { int av = edgs[v][i].adj; idegs[av] += 1; } }}void InitTopo() { topo0.clear();}void InitVst() { // 除了调用Kruskal()都需要 for (int v = 0; v < nvtx; v += 1) { vsts[v] = 0; dfps[v] = false; }}void InitDst() { for (int v = 0; v < nvtx; v += 1) { nums[v] = 0; dsts[v] = 0x7FFFFFFF; prvs[v].clear(); }}void InitMST() { // 仅当调用Prim()、Kruskal()才需要 mst0.clear();}void TravToposRcr(vector<int> &topo, int &cnt);int TravTopos() { InitVst(); InitDeg(); InitTopo(); vector<int> topo; int cnt = 0; TravToposRcr(topo, cnt); return cnt;}void TravToposRcr(vector<int> &topo, int &cnt) { if (topo.size() == nvtx) { for (int i = 0; i < topo.size(); i += 1) { int v = topo[i]; printf("%c", v2ns[v]); } printf("\n"); /* topo0 = topo; */ cnt += 1; } else { for (int v = 0; v < nvtx; v += 1) { if (idegs[v] == 0 && dfps[v] == false) { // 若只需一个拓扑排序则控制点的访问次数 /* if (vsts[v] == 0) { vsts[v] = 1; */ dfps[v] = true; topo.push_back(v); for (int i = 0; i < edgs[v].size(); i += 1) { int av = edgs[v][i].adj; idegs[av] -= 1; } TravToposRcr(topo, cnt); dfps[v] = false; topo.pop_back(); for (int i = 0; i < edgs[v].size(); i += 1) { int av = edgs[v][i].adj; idegs[av] += 1; } /* } else { // 特别注意若子图有多个拓扑排序但全图有环路则vsts[v] = 1 & cnt = 0 if (cnt != 0) { cnt = 2; } } */ } } }}// 遍历两点的所有路径(原始图)void TravPathsRcr(int v, int dvtx, vector<int> &path, int &cnt);int TravPaths(int svtx, int dvtx) { InitVst(); vector<int> path; int cnt = 0; TravPathsRcr(svtx, dvtx, path, cnt); return cnt;}void TravPathsRcr(int v, int dvtx, vector<int> &path, int &cnt) { dfps[v] = true; path.push_back(v); if (v == dvtx) { // 递归退出在到达终点 printf("%d", path[0]); for (int i = 1; i < path.size(); i += 1) { printf(" -> %d", path[i]); } printf("\n"); cnt += 1; } else { for (int i = 0; i < edgs[v].size(); i += 1) { int av = edgs[v][i].adj; if (dfps[av] == false) { TravPathsRcr(av, dvtx, path, cnt); } } } dfps[v] = false; // 点可经由多次 path.pop_back();}// 遍历两点的所有路径(前驱图)void TravPrevsRcr(int svtx, int v, vector<int> &path, int &cnt);int TravPrevs(int svtx, int dvtx) { InitVst(); vector<int> path; int cnt = 0; TravPrevsRcr(svtx, dvtx, path, cnt); return cnt;}void TravPrevsRcr(int svtx, int v, vector<int> &path, int &cnt) { dfps[v] = true; path.push_back(v); if (v == svtx) { // 递归退出在到达终点 printf("%d", path[path.size() - 1]); for (int i = path.size() - 2; i >= 0; i -= 1) { printf(" -> %d", path[i]); } printf("\n"); cnt += 1; } else { for (int i = 0; i < prvs[v].size(); i += 1) { int pv = prvs[v][i].vtx; if (dfps[pv] == false) { TravPrevsRcr(svtx, pv, path, cnt); } } } dfps[v] = false; // 点可经由多次 path.pop_back();}struct VtxDsj { int root; int rank; // 按高度秩合并};VtxDsj dsjs[NVTX_MAX];void InitVtxDsj() { for (int v = 0; v < nvtx; v += 1) { dsjs[v].root = v; dsjs[v].rank = 0; }}int FindVtxDsj(int v) { if (dsjs[v].root != v) { dsjs[v].root = FindVtxDsj(dsjs[v].root); } return dsjs[v].root;}void UnionVtxDsj(int v1, int v2) { int rv1 = FindVtxDsj(v1); int rv2 = FindVtxDsj(v2); if (rv1 != rv2) { if (dsjs[rv1].rank < dsjs[rv2].rank) { dsjs[rv1].root = rv2; } else { dsjs[rv2].root = rv1; if (dsjs[rv1].rank == dsjs[rv2].rank) { dsjs[rv1].rank += 1; } } }}void Kruskal() { InitVtxDsj(); InitMST(); priority_queue<Edg> epq; for (int v = 0; v < nvtx; v += 1) { for (int i = 0; i < edgs[v].size(); i += 1) { epq.push(edgs[v][i]); } } while (! epq.empty()) { Edg edg = epq.top(); epq.pop(); int v = edg.vtx, av = edg.adj; if (FindVtxDsj(v) != FindVtxDsj(av)) { mst0.push_back(edg); UnionVtxDsj(v, av); } }}int main() { while (true) { InitG(); if (! ScanG()) { break; } TravPaths(svtx, dvtx); // Dijkstra(svtx); ZOJ 1003 // Prim(); POJ 1258 & 2485 // Kruskal(); // TravTopos(); POJ 1270 & 1094 }}
除此之外,你
0 0
- 常规笔试算法 上部 练习版(练习编程必做)
- 常规笔试算法 下部 应试版(笔试编程必考)
- Poj 搜索练习, 必做(转)
- 算法练习必看
- [笔试] 编程练习小计
- 编程算法练习
- 编程算法练习
- 编程算法练习
- 编程算法练习(1.12)
- 编程算法练习
- 编程算法练习
- 编程算法练习
- MySQL常规练习
- 编程练习三(贪心算法)
- [笔试练习]
- 经典C++笔试题目--100(编程练习)(91-100)
- 笔试题练习(九)
- 笔试题练习(八)
- 166. Fraction to Recurring Decimal
- 【scikit-learn algorithm cheat sheet】【汉化版】scikit-learn算法选择路径图
- 常规笔试算法 下部 应试版(笔试编程必考)
- Medium 377题 Combination Sum IV
- Medium 64题 Minimum Path Sum
- 常规笔试算法 上部 练习版(练习编程必做)
- PAT考试重点真题选做(尽量参考学习)
- Master-Worker设计模式
- 【软件】system.new.dat一键解包工具,支持Android5.1
- 奶牛的锻炼
- 真有用?Snap和Flatpak 通吃所有发行版的打包方式。
- 开始了新的博客
- ORA-19573: cannot obtain exclusive enqueue for datafile XXX 解决方法
- JavaScript笔记:使用canvas绘图