题意:有一些骨牌,告诉你一些关系a->b表示a倒了b也会倒。然后问你最少要推到几个才能使所有的骨牌都倒下。
思路:这道题其实就是用的强连通分支的kosaraju算法。其实在了解了这个算法之后我们不妨来想想是怎么样的一个逻辑关系。第一遍dfs我们先得到了在vs数组中的拓扑关系。到了第二遍,我们就从拓扑序列高的先开始dfs(可以直观的了解到只要拓扑序列高的倒下了,那么拓扑序列低的必定倒下了)所以我们得到的dfs次数即为答案了。
代码如下:
1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao/ 4 * Last modified : 2014-01-28 22:16 5 * Filename : uva_11504.cpp 6 * Description : 7 * ************************************************/ 8 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <cstdlib> 13 #include <cmath> 14 #include <algorithm> 15 #include <queue> 16 #include <stack> 17 #include <vector> 18 #include <set> 19 #include <map> 20 #define MP(a, b) make_pair(a, b) 21 #define PB(a) push_back(a) 22 23 using namespace std; 24 typedef long long ll; 25 typedef pair<int, int> pii; 26 typedef pair<unsigned int,unsigned int> puu; 27 typedef pair<int, double> pid; 28 typedef pair<ll, int> pli; 29 typedef pair<int, ll> pil; 30 31 const int INF = 0x3f3f3f3f; 32 const double eps = 1E-6; 33 const int LEN = 100000+10; 34 vector<int> vs, Map[LEN]; 35 int vis[LEN], n, m, scct[LEN]; 36 37 void dfs(int v){ 38 vis[v] = 1; 39 for(int i=0; i<Map[v].size(); i++){ 40 if(!vis[Map[v][i]])dfs(Map[v][i]); 41 } 42 vs.PB(v); 43 } 44 45 void rdfs(int v, int f){ 46 vis[v] = 1; 47 scct[v] = f; 48 for(int i=0; i<Map[v].size(); i++){ 49 if(!vis[Map[v][i]])rdfs(Map[v][i], f); 50 } 51 } 52 53 int scc(){ 54 memset(vis, 0, sizeof vis); 55 vs.clear(); 56 for(int i=1; i<=n; i++)if(!vis[i])dfs(i); 57 memset(vis, 0, sizeof vis); 58 int f = 0; 59 for(int i=vs.size()-1; i>=0; i--){ 60 if(!vis[vs[i]])rdfs(vs[i], f++); 61 } 62 return f; 63 } 64 65 int main() 66 { 67 // freopen("in.txt", "r", stdin); 68 69 int T, a, b; 70 scanf("%d", &T); 71 while(T--){ 72 for(int i=0; i<LEN; i++)Map[i].clear(); 73 scanf("%d%d", &n, &m); 74 for(int i=0; i<m ;i++){ 75 scanf("%d%d", &a, &b); 76 Map[a].PB(b); 77 } 78 printf("%d\n", scc()); 79 } 80 return 0; 81 }