1. 程式人生 > >HDOJ 4582 - DFS spanning tree - DFS樹,貪心

HDOJ 4582 - DFS spanning tree - DFS樹,貪心

void 遞增 should 思路 while father head spa func

題目大意:

給定一個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 }

HDOJ 4582 - DFS spanning tree - DFS樹,貪心