标签:
题意:一个有向图中,若对于任意两个点s和t,要么存在一条从s到t的路径,要么存在一条t到s的路径(当然两条路径都存在也是可以的),那么称这个有向图是一个半联通图.现在给定一个有向图,求出该有向图中点数最多的半联通子图的点数以及个数.
很显然,在一个最优方案中,同一个强连通分量中的点要么都选,要么都不选.
很自然地,先用tarjan缩个点,得到一个有向无环图,每个点的点权为对应的强连通分量的点的个数.
然后稍微脑补一下,就知道第一问的答案显然是该有向无环图上最长链的长度,而第二问的答案自然也就是最长链的个数.
求这两问可以用有向无环图上的dp一起求出~
1 #include <set> 2 #include <stack> 3 #include <cstdio> 4 5 using namespace std; 6 7 const size_t Max_N(100050); 8 const size_t Max_M(1000050); 9 10 typedef pair<unsigned int, unsigned int> pll; 11 12 inline 13 unsigned int Min(const unsigned int &a, const unsigned int &b) 14 { 15 return a < b ? a : b; 16 } 17 18 void Get_Val(unsigned int &ret) 19 { 20 ret = 0; 21 char ch; 22 while ((ch = getchar()), (ch > ‘9‘ || ch < ‘0‘)) 23 ; 24 do 25 { 26 (ret *= 10) += ch - ‘0‘; 27 } 28 while ((ch = getchar()), (ch >= ‘0‘ && ch <= ‘9‘)); 29 } 30 31 size_t N, M; 32 unsigned int MOD; 33 unsigned int Head[Max_N]; 34 unsigned int To[Max_M], Next[Max_M]; 35 36 unsigned int SCC_Total; 37 unsigned int SCC_Number[Max_N]; 38 unsigned int SCC_Weight[Max_N]; 39 40 unsigned int SCC_Edge_Total; 41 unsigned int SCC_Head[Max_N]; 42 unsigned int SCC_To[Max_M], SCC_Next[Max_M]; 43 unsigned int SCC_Degree[Max_N]; 44 45 stack<unsigned int> S; 46 47 inline 48 void Add_Edge(const size_t &Total, const size_t &s, const size_t &t) 49 { 50 To[Total] = t, Next[Total] = Head[s], Head[s] = Total; 51 } 52 53 inline 54 void SCC_Add_Edge(const size_t &s, const size_t &t) 55 { 56 ++SCC_Edge_Total, SCC_To[SCC_Edge_Total] = t, SCC_Next[SCC_Edge_Total] = SCC_Head[s], SCC_Head[s] = SCC_Edge_Total; 57 } 58 59 void init() 60 { 61 Get_Val(N); 62 Get_Val(M); 63 Get_Val(MOD); 64 65 size_t A, B; 66 for (size_t i = 1;i <= M;++i) 67 { 68 Get_Val(A); 69 Get_Val(B); 70 Add_Edge(i, A, B); 71 } 72 } 73 74 unsigned int Dfs_Clock; 75 unsigned int Pre[Max_N], Low_Link[Max_N]; 76 77 void Tarjan(const size_t &u) 78 { 79 size_t v; 80 Pre[u] = Low_Link[u] = ++Dfs_Clock; 81 S.push(u); 82 83 for (size_t i = Head[u];i;i = Next[i]) 84 { 85 v = To[i]; 86 if (!Pre[v]) 87 { 88 Tarjan(v); 89 Low_Link[u] = Min(Low_Link[u], Low_Link[v]); 90 } 91 else 92 if (!SCC_Number[v]) 93 Low_Link[u] = Min(Low_Link[u], Pre[v]); 94 } 95 96 if (Pre[u] == Low_Link[u]) 97 { 98 ++SCC_Total; 99 while (true) 100 { 101 v = S.top(); 102 S.pop(); 103 SCC_Number[v] = SCC_Total; 104 ++SCC_Weight[SCC_Total]; 105 if (u == v) 106 break; 107 } 108 } 109 } 110 111 void Make_Graph() 112 { 113 set<pll> Judge; 114 size_t t; 115 116 for (size_t i = 1;i <= N;++i) 117 if (!Pre[i]) 118 Tarjan(i); 119 for (size_t s = 1;s <= N;++s) 120 for (size_t i = Head[s];i;i = Next[i]) 121 { 122 t = To[i]; 123 if (SCC_Number[s] != SCC_Number[t]) 124 if (!Judge.count(pll(SCC_Number[s], SCC_Number[t]))) 125 { 126 SCC_Add_Edge(SCC_Number[s], SCC_Number[t]); 127 ++SCC_Degree[SCC_Number[t]]; 128 Judge.insert(pll(SCC_Number[s], SCC_Number[t])); 129 } 130 } 131 } 132 133 unsigned int F[Max_N]; 134 unsigned int Cnt[Max_N]; 135 void dp() 136 { 137 unsigned int Max_Point(0); 138 unsigned int Max_Cnt(0); 139 for (size_t i = 1;i <= SCC_Total;++i) 140 if (!SCC_Degree[i]) 141 { 142 S.push(i); 143 F[i] = SCC_Weight[i]; 144 Cnt[i] = 1; 145 } 146 147 unsigned int Top; 148 unsigned int v; 149 while (S.size()) 150 { 151 Top = S.top(); 152 S.pop(); 153 for (size_t i = SCC_Head[Top];i;i = SCC_Next[i]) 154 { 155 v = SCC_To[i]; 156 if (F[v] < F[Top] + SCC_Weight[v]) 157 { 158 F[v] = F[Top] + SCC_Weight[v]; 159 Cnt[v] = Cnt[Top]; 160 } 161 else 162 if (F[v] == F[Top] + SCC_Weight[v]) 163 (Cnt[v] += Cnt[Top]) %= MOD; 164 --SCC_Degree[v]; 165 if (!SCC_Degree[v]) 166 S.push(v); 167 } 168 } 169 170 for (size_t i = 1;i <= SCC_Total;++i) 171 if (F[i] > Max_Point) 172 { 173 Max_Point = F[i]; 174 Max_Cnt = Cnt[i]; 175 } 176 else 177 if (F[i] == Max_Point) 178 (Max_Cnt += Cnt[i]) %= MOD; 179 printf("%u\n%u", Max_Point, Max_Cnt % MOD); 180 } 181 182 int main() 183 { 184 init(); 185 186 Make_Graph(); 187 dp(); 188 189 return 0; 190 }
标签:
原文地址:http://www.cnblogs.com/Created-equal/p/5027342.html