码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1093 [ZJOI2007]最大半连通子图

时间:2015-12-07 22:32:38      阅读:331      评论:0      收藏:0      [点我收藏+]

标签:

题意:一个有向图中,若对于任意两个点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 }
BZOJ 1093

 

BZOJ 1093 [ZJOI2007]最大半连通子图

标签:

原文地址:http://www.cnblogs.com/Created-equal/p/5027342.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!