HDOJ 4582 - DFS spanning tree - DFS树,贪心

题目大意:

给定一个N个点、M条边的无向图Graph,以及从点1开始进行DFS形成的树Tree,定义"T-Simple Circle"为Graph中的环,要求其中只含一条不属于Tree的边。

将Graph中的一些边进行染色,使得其中每个T-simple Circle都至少包含一条被染色的边,求最少需要染色的边数。

N≤2e3,M≤2e4

本题关键的一点在于Tree是一棵DFS生成树,这样Tree以外的边只可能将某个点与它在Tree中的祖先相连(用反证法可以证明,只有这样才能维持DFS树的性质)。

也就是说,每条Tree以外的边都相当于在DFS生成树上划定了一条深度单调递增(递减)的链,问题转化为:最少染色多少条边,可以使每条链上都至少有一条边被染色。

不难发现,对Tree以外的边进行染色的覆盖效率远小于对Tree上的边进行染色,因此只需考虑DFS生成树的边。

类比直线上的区间选点问题,本题也可以用类似的贪心思路。

题解:http://blog.csdn.net/sd_invol/article/details/9963741

直线上区间选点问题的证明:http://blog.csdn.net/dgq8211/article/details/7534776

C++11代码(貌似HDOJ可以交C++11?):

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <functional>
  6 
  7 const int maxN = 2000 + 5;
  8 const int maxM = 20000 + 5;
  9 
 10 std::vector<int> toVec[maxN];
 11 int father[maxN]; //father in the DFS tree
 12 int depth[maxN]; //depth in the DFS tree
 13 bool covered[maxN]; //whether the edge (x - father[x]) is covered (used in greedy algorithm)
 14 
 15 struct Range
 16 {
 17     int head, tail; //We guarantee that depth[head] >= depth[tail]
 18 
 19     void swapEndPoint()
 20     {
 21         if (depth[head] < depth[tail])
 22             std::swap(head, tail);
 23     }
 24     bool operator < (const Range& rhs) const
 25     {
 26         return depth[tail] > depth[rhs.tail] ||
 27                 (depth[tail] == depth[rhs.tail] && depth[head] < depth[rhs.head]);
 28         //high depth -> 0 --- 0 --- 0 --- 0 --- 0 -> low depth
 29         //greater:            x --------- x
 30         //less:         x --------------------- x
 31     }
 32 };
 33 
 34 Range range[maxM];
 35 int N, M;
 36 
 37 void init()
 38 {
 39     memset(father, 0, sizeof(father));
 40     memset(depth, 0, sizeof(depth));
 41     memset(covered, 0, sizeof(covered));
 42     for (int i = 1; i <= N; i++)
 43         toVec[i].clear();
 44 }
 45 
 46 /// @brief swap head and tail so that depth[head] >= depth[tail]
 47 ///        this function is called after depth[] is set, before sorting ranges for greedy algorithm
 48 void initRange()
 49 {
 50     for (int i = 0; i < M - N + 1; i++)
 51         range[i].swapEndPoint();
 52 }
 53 
 54 bool input()
 55 {
 56     scanf("%d%d", &N, &M);
 57     if (N == 0)
 58         return false;
 59 
 60     init();
 61     for (int u, v, i = 0; i < N - 1; i++) //(N - 1) Edges in DFS tree
 62     {
 63         scanf("%d%d", &u, &v);
 64         toVec[u].push_back(v);
 65         toVec[v].push_back(u);
 66     }
 67     for (int u, v, i = N - 1; i < M; i++)
 68     {
 69         scanf("%d%d", &u, &v);
 70         range[i - N + 1] = {u, v}; //The end points may be swapped later
 71     }
 72 
 73     return true;
 74 }
 75 
 76 ///@brief DFS process, setting depth[] and father[]
 77 void dfs(int cur, int last)
 78 {
 79     father[cur] = last;
 80     depth[cur] = depth[last] + 1;
 81     for (auto to: toVec[cur])
 82     {
 83         if (to == last)
 84             continue;
 85         dfs(to, cur);
 86     }
 87 }
 88 
 89 ///@brief wrapper of DFS function
 90 void setDepthAndFather()
 91 {
 92     depth[0] = 0;
 93     dfs(1, 0); 
 94 }
 95 
 96 int solve()
 97 {
 98     setDepthAndFather();
 99     initRange();
100     std::sort(range, range + M - N + 1); //(M - N + 1) Edges that does not belong to the DFS tree
101 
102     ///@return last if edge (last, father[last]) should be covered
103     ///        0 if no edge should be covered in this chain
104     auto getCoverEdge = [] (const Range& rg) -> int
105     {
106         int last = rg.head;
107 
108         //higher depth -> head -> tail -> lower depth
109         for (int cur = rg.head; cur != rg.tail; cur = father[cur])
110         {
111             if (covered[cur])
112                 return 0;
113             last = cur;
114         }
115         return last;
116     };
117 
118 //    ///@debug
119 //    for (int i = 1; i <= N; i++)
120 //        printf("father[%d] = %d, depth[%d] = %d\n", i, father[i], i, depth[i]);
121 
122     int ans = 0;
123     for (int i = 0; i < M - N + 1; i++)
124     {
125         int coverId = getCoverEdge(range[i]);
126         if (coverId == 0)
127             continue;
128         ans += 1;
129         covered[coverId] = true;
130     }
131 
132     return ans;
133 }
134 
135 int main()
136 {
137     while (input())
138         printf("%d\n", solve());
139     return 0;
140 }

 

转载于:https://www.cnblogs.com/Onlynagesha/p/8448560.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值