常规笔试算法 上部 练习版(练习编程必做)

来源:互联网 发布:电脑恢复手机数据 编辑:程序博客网 时间: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
原创粉丝点击