zoukankan      html  css  js  c++  java
  • 华为软挑 2020 4_19 浮生日记

    简介

    还是强调一下,本人菜鸡一枚,但是对于顶级coder也是很向往的,今年因为个人的原因可能不能走的很远。但是还是想多学习一下。以下代码来自 --大学 同学,杨菲菲

    提升思路

    加速 IO
    多线程
    减少内存的申请和释放
    更新算法

    code

    /*
     * @Author: your name
     * @Date: 2020-04-17 10:43:11
     * @LastEditTime: 2020-04-17 10:43:42
     * @LastEditors: Please set LastEditors
     * @Description: In User Settings Edit
     * @FilePath: codelesson_1.cpp
     */
    
    #define _LINUX
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <unordered_map>
    #include <algorithm>
    #include <fstream>
    #include <thread>
    #include <cstring>
    #include <time.h>
    
    #ifdef _LINUX
    #include <sys/mman.h>
    #include <unistd.h>
    #include <fcntl.h>
    #endif
    
    #define _CRT_SECURE_NO_WARNINGS  // 防止 fopen 和 fscanf 报错
    
    static bool vis[600000];
    static int Gout[600000][100];    // 记录出边, Gout[i][j]表示结点i第j条出边所连接的结点 
    static int Gin[600000][500];     // 记录入边, Gin[i][j]表示结点i第j条入边所连接的结点 
    static int pOut[600000];         // 每个结点出边索引j 
    static int pIn[600000];          // 每个结点入边索引
    
    struct Path {
        // ID最小的第一个输出;
        // 总体按照循环转账路径长度升序排序;
        // 同一级别的路径长度下循环转账账号ID序列,按照字典序(ID转为无符号整数后)升序排序
        int length;
        std::vector<unsigned int> path;
    
        Path(int length, const std::vector<unsigned int> &path) : length(length), path(path) {}
    
        bool operator<(const Path&rhs)const 
        {   //在排序的时候有用
            if (length != rhs.length) return length < rhs.length; // length 从小到大
            for (int i = 0; i < length; i++) {
                if (path[i] != rhs.path[i])   // 字典序
                    return path[i] < rhs.path[i];
            }
        }
    };
    
    class Solution {
    public:
        std::unordered_map<unsigned int, int> idHash;    // sorted id to 0...n 
        std::vector<unsigned int> ids;                   // 0...n to sorted id
        std::vector<unsigned int> inputs;                // u-v pairs 
        std::vector<int> path;
        std::vector<Path> ans;
        int nodeCnt;
        
    #ifdef _LINUX
        void parseInput(std::string &testFile)
        {
            int fd = open(testFile.c_str(), O_RDONLY);
            int len = lseek(fd, 0, SEEK_END);
            char *mbuf = (char *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
            if(fd != -1) {
                close(fd);  
            }
            unsigned int offset = 0, cnt = 0;;
            unsigned int u, v, c;
            for(int i = 0; i < len; i++) {
                if(mbuf[i] == '
    ') {
                    mbuf[i] = '';
                    sscanf(mbuf + offset, "%u,%u,%u", &u, &v, &c);
                    offset = i + 2;   // 跳过 /r/n 
                    inputs.push_back(u);
                    inputs.push_back(v);
                    ++cnt;
                }
            }
            munmap(mbuf, len); 
        }
    #else
        void parseInput(std::string &testFile) 
        {
            FILE* file = fopen(testFile.c_str(), "r");
            unsigned int u, v, c;
            int cnt = 0;
            while (fscanf(file, "%u,%u,%u", &u, &v, &c) != EOF) {
                inputs.push_back(u);
                inputs.push_back(v);
                ++cnt;
            }
            if(file != NULL) {
                fclose(file);
            }
            
    #ifdef TEST
            printf("%d Records in Total
    ", cnt);  // 输出总共存储了多少条数据
    #endif
    
        }
    #endif
    
        void constructGraph() 
        {
            std::vector<unsigned int> tmp = inputs;
            sort(tmp.begin(), tmp.end()); // 对所有id进行排序
            tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end()); // 独一无二的tmp了
            ids = tmp;
            nodeCnt = 0;
            
            for(int i = 0; i < tmp.size(); i++) {
                idHash[tmp[i]] = nodeCnt++;
            }
            
    #ifdef TEST
            printf("%d Nodes in Total
    ", nodeCnt);
    #endif
    
            int sz = inputs.size();
            memset(pOut, 0, sizeof(pOut));
    		memset(pIn, 0, sizeof(pIn));
            for (int i = 0; i < sz; i += 2) {
                int u = idHash[inputs[i]], v = idHash[inputs[i + 1]];
                Gout[u][pOut[u]++] = v;
                Gin[v][pIn[v]++] = u;
            }
        }
    
        void dfs(int head, int cur, int depth) 
        {
            vis[cur] = true;       // 当前节点已经访问过
            path.push_back(cur);   // 路径中存入当前节点
            for(int i = 0; i < pOut[cur]; i++) {
                int v = Gout[cur][i];
                if (v == head && depth >= 3 && depth <= 7) { // 如果当前节点的一个出度是头结点,那么就是一个答案
                    std::vector<unsigned int> tmp;
                    for(int j = 0; j < path.size(); j++)
                        tmp.push_back(ids[path[j]]);
                    ans.emplace_back(Path(depth, tmp));  // 等于push_back 不会触发 不需要触发拷贝构造和转移构造
                }
                if (depth < 7 && !vis[v] && v > head) {
                    dfs(head, v, depth + 1);
                }
            }
            vis[cur] = false;
            path.pop_back();
        }
    
        // search from 0...n
        // 由于要求id最小的在前,因此搜索的全过程中不考虑比起点id更小的节点
        void solve() 
        {
            for (int i = 0; i < nodeCnt; i++) {
                if (pOut[i] && pIn[i]) { // 如果节点i对应的节点 有出度的话开启这个节点的dfs
                    dfs(i, i, 1);
                }
            }
            sort(ans.begin(), ans.end());
        }
    
        void save(std::string &outputFile)
        {
            std::ostringstream os;
            os << ans.size() << std::endl;
            
            for(int k = 0; k < ans.size(); k++) {
                std::vector<unsigned int> path = ans[k].path;
                int sz = path.size();
                os << path[0];
                for (int i = 1; i < sz; i++) {
                    os << "," << path[i];
                }
                os << std::endl;
            }
            FILE * fp = fopen(outputFile.c_str(), "w" );
            fwrite(os.str().c_str(), os.str().length(), 1, fp);
            fclose(fp);
        }
    };
    
    int main()
    {
        std::string testFile = "/data/test_data.txt";
        std::string outputFile = "/projects/student/result.txt";
        
    #ifdef TEST
        std::string answerFile = "C:/Users/lee/Desktop/code/华为软件精英挑战赛/初赛/初赛赛题/result.txt";
    #endif
    
        Solution solution;             // 构建一个解决方案类
        solution.parseInput(testFile); // 读取数据将 id1,id2,money  id1和id2 存储在 std::vector<unsigned int> inputs; 
        solution.constructGraph();     // 构建图
        //solution.topoSort();
        solution.solve();              //解决它
        solution.save(outputFile);
        return 0;
    }
    

    分数

    5.5

    结论

    内存的申请和释放占据了大量时间。读取数据和写入数据 采用的mmap可以加速数据的读取和写入

    Hope is a good thing,maybe the best of things,and no good thing ever dies.----------- Andy Dufresne
  • 相关阅读:
    stack.pop()和stack.peek()的区别
    信号与系统,系统函数的影响
    java中short、int、long、float、double取值范围
    Spring从容器获得组件的方法
    Eclipse中项目的类路径文件夹
    Math的常用方法
    spring基本入门步骤
    opencv入门
    make和cmake构建工具
    使用eclipse开发c++程序及开发环境搭建
  • 原文地址:https://www.cnblogs.com/eat-too-much/p/12734559.html
Copyright © 2011-2022 走看看