• 【做题】Codeforces Round #436 (Div. 2) F. Cities Excursions——图论+dfs


    题意:给你一个有向图,多次询问从一个点到另一个点字典序最小的路径上第k个点。

    考虑枚举每一个点作为汇点(记为i),计算出其他所有点到i的字典序最小的路径。(当然,枚举源点也是可行的)

    首先,我们建一张反向图,从i开始dfs,以删去所有无法到达i的点。

    然后,因为此时图上所有点都可以到达i,所以可以贪心地在从每一个点出发的边中只保留终点编号最小的边,而把其他边删除。

    这样就可以保证路径是字典序最小的,并且从每个点到i的路径只有一条。

    而题目中给出了这样一种情况:

    • there are paths from sj to tj, but for every such path p there is another path q from sj to tj, such that pi > qi, where i is the minimum integer for which pi ≠ qi.

    因此最后可能某些未被删去的点无法到达i,就需要从i开始再dfs一遍,以删去这些点。

    在最后这次dfs的同时通过倍增记录路径(即祖先节点),以实现O(logn)地查询路径的第k个点。

    时间复杂度O(n^2*logn+q*logn)。

      1 #include <bits/stdc++.h>
      2 #define travel(i,x,p) for(int i=p.fir[(x)];i;i=p.con[i].la)
      3 #define nex(x,p) p.con[x].b
      4 using namespace std;
      5 const int N=3010,Q=400010;
      6 struct edge{
      7     int la,b;
      8 };
      9 struct graph{
     10     edge con[N];
     11     int tot,fir[N];
     12     bool vis[N];
     13     void init()
     14     {
     15         tot=0;
     16         memset(fir,0,sizeof fir);
     17     }
     18     void add(int from,int to)
     19     {
     20         con[++tot].la=fir[from];
     21         con[tot].b=to;
     22         fir[from]=tot;
     23     }
     24     void dfs(int pos)
     25     {
     26         vis[pos]=1;
     27         for(int i=fir[pos];i;i=con[i].la)
     28         {
     29             if(!vis[con[i].b]) dfs(con[i].b);
     30         }
     31     }
     32 }p1,p2,p3;
     33 int n,m,q,anc[N][13];
     34 struct query{
     35     int s,k,id;
     36 };
     37 vector<query>ask[N];
     38 int ans[Q];
     39 void exdfs(int pos)
     40 {
     41     p3.vis[pos]=1;
     42     for(int i=1;i<=12;i++)
     43         anc[pos][i]=anc[anc[pos][i-1]][i-1];
     44     for(int i=p3.fir[pos];i;i=p3.con[i].la)
     45     {
     46         anc[p3.con[i].b][0]=pos;
     47         exdfs(p3.con[i].b);
     48     }
     49 }
     50 void doit(query tmp,int pos)
     51 {
     52     if(!p3.vis[tmp.s]) ans[tmp.id]=-1;
     53     else
     54     {
     55         tmp.k--;
     56         pos=tmp.s;
     57         for(int i=12;i>=0;i--)
     58         {
     59             if((1<<i)<=tmp.k)
     60                 tmp.k-=(1<<i),pos=anc[pos][i];
     61         }
     62         if(pos==0) ans[tmp.id]=-1;
     63         else ans[tmp.id]=pos;
     64     }
     65 }
     66 void solve(int pos)
     67 {
     68     memset(p2.vis,0,sizeof p2.vis);
     69     p2.dfs(pos);
     70     p3.init();
     71     int tmp;
     72     for(int i=1;i<=n;i++)
     73     {
     74         if(p2.vis[i]&&i!=pos)
     75         {
     76             tmp=n+1;
     77             travel(j,i,p1)
     78             {
     79                 if(p2.vis[nex(j,p1)]&&nex(j,p1)<tmp)
     80                     tmp=nex(j,p1);
     81             }
     82             if(tmp!=n+1) p3.add(tmp,i);
     83         }
     84     }
     85     memset(p3.vis,0,sizeof p3.vis);
     86     memset(anc,0,sizeof(anc));
     87     exdfs(pos);
     88     for(int i=0;i<(int)ask[pos].size();i++)
     89     {
     90         doit(ask[pos][i],pos);
     91     }
     92 }
     93 int main()
     94 {
     95     int from,to;
     96     scanf("%d%d%d",&n,&m,&q);
     97     for(int i=1;i<=m;i++)
     98     {
     99         scanf("%d%d",&from,&to);
    100         p1.add(from,to);
    101         p2.add(to,from);
    102     }
    103     int x,y,k;
    104     for(int i=1;i<=q;i++)
    105     {
    106         scanf("%d%d%d",&x,&y,&k);
    107         ask[y].push_back((query){x,k,i});
    108     }
    109     for(int i=1;i<=n;i++)
    110         solve(i);
    111     for(int i=1;i<=q;i++)
    112         printf("%d
    ",ans[i]);
    113     return 0;
    114 }

    小结:在诸如最小字典序路径和其他问题中,可以通过预处理以保证贪心的正确性。

  • 相关阅读:
    RabbitMQ第一次不能正常读取第二次正常的问题
    ng跳转映射,被阿里云的云盾拦截,提示备案问题分析
    Java读取excel表,getPhysicalNumberOfCells()和getLastCellNum区别
    IDEA同步上传lua代码,方便开发。
    redis安装
    面试感悟----一名3年工作经验的程序员应该具备的技能
    SQL Server的case when用法
    SQL Server常用函数使用方法(学习)
    Openresty编写Lua代码一例
    Nginx的配置文件nginx.conf解析
  • 原文地址:https://www.cnblogs.com/cly-none/p/7656368.html
Copyright © 2020-2023  润新知