zoukankan      html  css  js  c++  java
  • 3月2-第八次机试课记录

    图论

    • dij使用地图是带权图

      • 记得初始化为INF
      • 无边的权值是INF,不是0,并且这个INF别用INT_MAX这个宏,会导致出现一些问题,比如dij更新路径的时候,INT_MAX + 1会变成负值,出错,自己定义一个比较大的数就行了
      const int INF = 1e9 + 7;
      

    思路与总结

    • 注意题目意识的转化,要把那些关键的信息抽象出来,比如小偷的移动东西就是可以抽象成为有向树,进而转化为找权值最大的树的根问题。
    • 其次要知道每个图相关的算法可以解决什么方面的问题,也就是你拥有那些工具:最短距离是找最短路径算法。涉及全局点的最优值,就是最小生成树。
    • 与图相关的算法
      • dfs/bfs
      • 最小生成树(prim + krusk)
      • 最短路径(dij + floyd)
      • 并查集
      • 拓扑排序
    • 注意初始化的值,不一定全是-1和0,比如dij的地图无法联通是INF
    • 无向图初始化要两次
    • 不仅是状态数组需要重新更新,地图在多组数据也要clear

    题号

    • PIPIOJ 1382: PIPI染色

    • PIPIOJ 1010: 好坑的电子地图

    • PIPIOJ 1117: 吝啬的PIPI

    • PIPIOJ 1384: PIPI的飞行路线

    • PIPIOJ 1182: 公交车站

    • PIPIOJ 1115: PIPI的聚会

    • PIPIOJ 1202: 侦探PIPI

    • PIPIOJ 1383: 院长PIPI

    • PIPIOJ 1183: 信使PIPI

    • PIPIOJ 1122: PIPI的比赛

    分析

    • 1010

      • 对地图的预处理,将不同奇数偶数的区别直接计算在地图上,ok了
    • 1117

      • 同样要对地图预处理
      • 同时这题在dij的时候搜索与更新路径是不一样的
        • 搜索是找最大保留路径
        • 更新是根据乘法更新路径信息
      • 这题还有个坑在与无法转账不是无法访问到这个点,而是最后的保留率为0,因为还可以包含给的数据直接收手续费全收取了
    • 1384

      • 使用优化的dij,主要在于使用矩阵的dij每次找最小点需要on的复杂度,现在使用优先队列,可以优化查询时间

      • 其次这题本来是打算使用dfs计算所有到达终点的路径,然后登记路径上可能的最大免费路径,但是答案给出的方法更加巧妙,使用两次dij,一次从起点到各个点,一次从终点到各个点,然后枚举免费路径,利用上面两个数组来维护最小开销

        //使用优先队列优化的dij
        struct Node{
        	int t;//对应点
        	int cost;//对应点的开销,不一定是最小,即为过程值,在过程中逐渐变为最优解
        	bool operator < (const Node &node) const{
                return cost > node.cost;//定义优先级
        	}
        }
        
        const int INF = 1e9;
        
        vector<Node> mp[N];//连接表
        int dist[N];//维护各个点的最小距离
        
        void dij(int s){
        	for(int i = 1; i <= n; i ++)
        		dist[i] = INF;
        	dist[s] = 0;
        	priority_queue<Node> Q;
        	Q.push({s, 0});
        	while(! Q.empty()){
        		Node now = Q.top();Q.pop();
        		
        		if(now.cost > dist[now.t])continue;//比最小的距离都大,没必要访问
        		//就是正常的更新路径
        		for(int i = 0; i < mp[now.t].size(); i ++){
        			Node next = mp[now.t][i];
        			if(dist[next.t] > now.cost + next.cost){//注意是now.cost不是dist[now.t]
        				dist[next.t] = now.cost + next.cost;
        				Q.push({next.t, dist[next.t]});
        			}
        		}
        	}
        }
        
        
        
    • 1115

      • 这题使用并查集,注意数据n和N是不一样的,朋友的下标并不在n之中,n只是查询的次数
    • 1202

      • 这题完全就是问题转化,如果将小偷的动向看成是有向图,那么问题就清楚起来的,也不用去考虑说动态的去找最优先,问题变成静态的找换或者找最多权的根
      • 使用并查集去达到这个目标
    • 1383

      • 这题就是问题的转化,从结果去想,所有的人一定都会加入,每两个的关系看成一条边,每加入一条边,就可以减去对应的费用,问题就转化成为了最小生成树(上面这个过程就是kruskal的过程)
      • kruskal过程需要借助并查集
    • 1183

      • 多次bfs将矩阵信息从地图矩阵中抽离出来,然后借助prim找最小生成树即可
      • 这题要区别bfs和最小生成树,bfs是在地图上跑的,而prim是在描述两者信息的矩阵上跑的,这题明显看出来
      • 其次,我本来想着一次bfs,然后最大的那个点的值就是结论,这样是错的,因为这样刚好是:当起点是最小生成树的中间点的时候,最小生成树的值刚好和bfs到最远点相同。但是起点不一定是中间点。
      • 我还想着多次bfs可以不用,一次bfs后,给每个教学楼打上时间戳,时间梯度差就是两点的距离,这样也是错的,还是最小生成树中间点是起点,两个端点a和b,a和b的最小距离可以是经过起点后才能计算,那么上面的结论完全错了,这个结论依赖两个端点直通才能有这个结论,如果不直通,那么就是错误的
    • 1122

      • 就是拓扑排序了,为了使得小的数字先数组使用了优先队列

        //优先队列是权值越大越先输出,即为递减队列
        priority_queue<int> Q;//默认是递减队列
        priority_queue<int, vector<int>, less<int> > Q;//等价于这个
        
        //递增队列
        priority_queue<int, vector<int>, greater<int> > Q;
        
  • 相关阅读:
    测试与发布
    Alpha阶段敏捷冲刺---Day7
    Alpha阶段敏捷冲刺---Day6
    Alpha阶段敏捷冲刺---Day4
    Alpha阶段敏捷冲刺---Day3
    201521123002《Java程序设计》第11周学习总结
    201521123002《Java程序设计》第10周学习总结
    201521123002《Java程序设计》第9周学习总结
    201521123002《Java程序设计》第8周学习总结
    201521123002《Java程序设计》第7周学习总结
  • 原文地址:https://www.cnblogs.com/faberry/p/12399083.html
Copyright © 2011-2022 走看看