码迷,mamicode.com
首页 > Web开发 > 详细

BZOJ 2208 [Jsoi2010]连通数

时间:2015-12-06 20:58:27      阅读:325      评论:0      收藏:0      [点我收藏+]

标签:

题意:给定一个有向图,求出该有向图中有多少个点对<x,y>,使x可以达到y。(x和y相等的情况也算)

 

首先,很显然,若a和b两个点在同一个强连通分量中,那么一定满足:

(1)a和b互相可达

(2)a能达到的点数和b能达到的点数相等

那么二话不说肯定是用tarjan缩点啦~点权自然是对应强连通分量的点个数

 

然后缩完点之后统计方案就不是很会了。。

一开始只想到了对缩点后的图跑一遍Floyd传递闭包,然后用乘法原理统计一下答案

然而这样的话时间复杂度就是O(n^3)了,那还不如不缩点直接原图跑传递闭包呢。。也是O(n^3)的

 

最后看了题解才知道怎么做。。对缩点后的dag跑dp。。

设F[i][j]为一个二进制位(每个F[i]都是一个bitset),表示能否从j达到i

然后初始化自然是F[i][i]=true

然后做拓扑排序,顺便跑动态规划。状态转移方程是F[j]|=F[i]  (i与j之间有边)

最后答案就是所有的weight[i]*weight[j]之和 (weight是某个点的点权,并且F[i][j]为true)

 

技术分享
  1 #include <queue>
  2 #include <stack>
  3 #include <cstdio>
  4 #include <bitset>
  5 
  6 using namespace std;
  7 
  8 const size_t Max_N(2050);
  9 
 10 size_t N;
 11 char Graph[Max_N][Max_N];
 12 
 13 unsigned int SCC_Total;
 14 unsigned int SCC_Number[Max_N];
 15 unsigned int SCC_Graph[Max_N][Max_N];
 16 unsigned int SCC_Weight[Max_N];
 17 unsigned int SCC_Degree[Max_N];
 18 
 19 inline
 20 unsigned int Min(const unsigned int &a, const unsigned int &b)
 21 {
 22     return a < b ? a : b;
 23 }
 24 
 25 void init()
 26 {
 27     scanf("%u", &N);
 28     for (size_t i = 1;i <= N;++i)
 29     {
 30         scanf("%s", Graph[i] + 1);
 31         for (size_t j = 1;j <= N;++j)
 32             Graph[i][j] -= 0;
 33     }
 34 }
 35 
 36 unsigned int Dfs_Clock;
 37 unsigned int Pre[Max_N], Low_Link[Max_N];
 38 stack<unsigned int> S;
 39 void Tarjan(const size_t &u)
 40 {
 41     size_t v;
 42     
 43     Pre[u] = Low_Link[u] = ++Dfs_Clock;
 44     S.push(u);
 45     
 46     for (v = 1;v <= N;++v)
 47         if (Graph[u][v])
 48             if (!Pre[v])
 49             {
 50                 Tarjan(v);
 51                 Low_Link[u] = Min(Low_Link[u], Low_Link[v]);
 52             }
 53             else
 54                 if (!SCC_Number[v])
 55                     Low_Link[u] = Min(Low_Link[u], Pre[v]);
 56     
 57     if (Pre[u] == Low_Link[u])
 58     {
 59         ++SCC_Total;
 60         while (true)
 61         {
 62             v = S.top();    
 63             S.pop();
 64             SCC_Number[v] = SCC_Total;
 65             ++SCC_Weight[SCC_Total];
 66             if (u == v)
 67                 break;
 68         }
 69     }
 70 }
 71 
 72 void Make_Graph()
 73 {
 74     for (size_t i = 1;i <= N;++i)
 75         if (!Pre[i])
 76             Tarjan(i);
 77     for (size_t s = 1;s <= N;++s)
 78         for (size_t t = 1;t <= N;++t)
 79             if (Graph[s][t] && SCC_Number[s] != SCC_Number[t])
 80                 if (!SCC_Graph[SCC_Number[s]][SCC_Number[t]])
 81                 {
 82                     SCC_Graph[SCC_Number[s]][SCC_Number[t]] = true;
 83                     ++SCC_Degree[SCC_Number[t]];
 84                 }
 85 }
 86 
 87 bitset<Max_N> F[Max_N];
 88 queue<unsigned int> Q;
 89 void dp()
 90 {
 91     for (size_t i = 1;i <= SCC_Total;++i)
 92         F[i][i] = true;
 93     for (size_t i = 1;i <= SCC_Total;++i)
 94         if (!SCC_Degree[i])
 95             Q.push(i);
 96     
 97     unsigned int Top;
 98     while (Q.size())
 99     {
100         Top = Q.front();
101         Q.pop();
102         for (size_t i = 1;i <= SCC_Total;++i)
103             if (SCC_Graph[Top][i])
104             {
105                 --SCC_Degree[i];
106                 F[i] |= F[Top];
107                 if (!SCC_Degree[i])
108                     Q.push(i);
109             }
110     }
111 }
112 
113 void Get_Ans()
114 {
115     unsigned int Ans(0);
116     for (size_t i = 1;i <= SCC_Total;++i)
117         for (size_t j = 1;j <= SCC_Total;++j)
118             if (F[i][j])
119                 Ans += SCC_Weight[i] * SCC_Weight[j];
120     printf("%u", Ans);
121 }
122 
123 int main()
124 {
125     init();
126     
127     Make_Graph();
128     dp();
129     Get_Ans();
130     
131     return 0;
132 }
BZOJ 2208

 

BZOJ 2208 [Jsoi2010]连通数

标签:

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

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