• 转发帖子链[CodeForces-522A]


    Reposts[CodeForces-522A]

    VK Cup 2015 - Qualification Round 1

    时间限制 1000ms 内存限制  256MB

    这道题主要是求最大遍历深度,不难想到用DFS解。这道题数据量不大,暴搜可以直接过,所以本身题目没啥难度,只是建图的时候要用map处理一下字符串和图的顶点的对应关系。但是自己的DFS写的真叫一个狗屎,索性好好分析一下DFS的整个过程,来作为这道题的题解。

    在算法导论书中,给出了进行DFS所需要的必备的储存信息:

    当前顶点需要一个前驱$v.π$,用来跟踪DFS结束时构成的深度优先树。,当前顶点被访问到的时间戳$v.d$和完全访问后染成黑色的时间戳$v.f$(实际上,$v.d$也可以理解为跟源节点到当前位置的距离有关,也就是和深度有关,而$v.f$是回溯时才记录,跟深度就不好相关了。),除此之外,还需要一个染色$v.color$,用来记录当前顶点的颜色。其实这个染色的属性是用来判断当前节点走没走过,在算导书中提及,染色节点只要包括两种颜色就行了,因此实际上只需要一个布尔值。

    DFS的开始,是在给定的图$G(V,E)$中,选择每一个可能的顶点,也就是$∀u∈G.V$,依次进行DFS。二叉树的DFS遍历,其实就是图的DFS的特例,因为二叉树的起始顶点只有树根。在DFS过程中,设当前顶点为$u$,先将$u$染色为$black$($u.color=black$),然后选择所有有边连接的顶点$∀u′∈G:Adj[u]$,判断是否被染色,对于没有染色,也就是没有走过的顶点继续进行DFS,直到没有顶点可以走为止。没有顶点可以走,意味着所有的顶点都被染色了,或者直接这个顶点没有连接任何下一个顶点。实际上,在上述描述的DFS过程中,无需额外设置递归的出口,因为选择合法的$u′$已经暗含了递归出口。需要注意,当DFS子过程回溯到主体过程时,需要重置所有顶点的染色标记和前驱标记。

    下面考虑具体实现的问题:一是图选择何种表示方法。通常情况下,稀疏图采用邻接表的方法,这样能够避免大量的空间浪费。因为采用邻接矩阵的方法,有$V$个顶点的图,就需要$V×V$的矩阵,也就是$V^2$的空间;并且搜索时,必须依次扫描当前顶点是不是存在着到别的顶点的边,因此总的时间复杂度是$O(V^2)$,在假定稀疏图$E<<V$的情况,邻接矩阵相较于邻接表的$O(V+E)$还是较慢的。对于邻接表中的表,通常的定义为链表,但是能够自由扩张的顺序数据结构都是可以的。因此我在做题的时候,采用了STL中的vector容器,来作为图的邻接表表示。至于染色属性的选择,既可以将图的每一个顶点定义成结构体,也可以单独设置数组,作为染色标记。我在这里采用了后一种的处理方法。

    对于数组作为邻接表的表示方法,我一开始把下标搞混了,一直得不到正确的结果。以我写的DFS过程为例,id参数表示当前顶点,用一个循环遍历vector容器表示的邻接表寻找有边连接的下一个顶点,因此判断下一个顶点是否被染色时,gone数组的下标实际上是下一个顶点graph[id][i],而不是idi的任意一个,i在这里表示用vector容器实现的邻接表在当前为id的顶点所包含的相邻的第i个顶点。除此之外,试图将判重和记录深度用一个属性来表示,似乎并不可行。

    下面给出我AC的完整代码,供参考。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<string>
     4 #include<vector>
     5 #include<map>
     6 #include<algorithm>
     7 using namespace std;
     8 map<string, int> mapper;
     9 vector<int> graph[205];
    10 int gone[205];
    11 int n;
    12 int cnt = 0;
    13 int ans = -2;
    14 int proc(string & s)
    15 {
    16     for (int i = 0; i < s.size(); i++)
    17         if (s[i] >= 'A'&&s[i] <= 'Z')s[i] += 32;
    18     map<string, int>::iterator it = mapper.find(s);
    19     if (it == mapper.end())
    20     {
    21         mapper.insert(pair<string, int>(s, cnt));
    22         return cnt++;
    23     }
    24     return it->second;
    25 }
    26 void dfs(int id, int time)
    27 {
    28     gone[id] = 0;
    29     for (int i = 0; i < graph[id].size(); i++)
    30     {
    31         if(gone[graph[id][i]]!=-1||graph[graph[id][i]].empty())
    32         {
    33             ans = max(ans, time + 1);
    34             return;
    35         }
    36         dfs(graph[id][i], ++time);
    37     }
    38 }
    39 int main()
    40 {
    41     cin >> n;
    42     string tmp1, tmp2;
    43     while (n--)
    44     {
    45         cin >> tmp1;
    46         cin >> tmp2;
    47         cin >> tmp2;
    48         int id1 = proc(tmp1);
    49         int id2 = proc(tmp2);
    50         graph[id1].push_back(id2);
    51     }
    52     for (int i = 0; i < cnt; i++)
    53     {
    54         for (int j = 0; j < 205; j++)gone[j] = -1;
    55         dfs(i, 0);
    56     }
    57     cout << ans + 1;
    58     return 0;
    59 }

     

     ,

  • 相关阅读:
    RAID技术
    Mysql的用户基本操作
    LNMP之Php的安装配置
    java 实现图片拼接
    java 实现Serv-U FTP 和 SFTP 上传 下载
    Image合并添加文字内容
    AOP切面用于系统日志
    网页评论实现
    java web 实体类生成
    java接口调试思想
  • 原文地址:https://www.cnblogs.com/ggggg63/p/6767831.html
Copyright © 2020-2023  润新知