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;
      
posted @ 2020-03-02 23:57  fabe2ry  阅读(248)  评论(0编辑  收藏  举报