题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861
题目大意:一个有向图,让你按规则划分区域,要求划分的区域数最少。
规则如下:1、有边u到v以及有边v到u,则u,v必须划分到同一个区域内。2、一个区域内的两点至少要有一方能到达另一方。3、一个点只能划分到一个区域内。
解题思路:根据规则1可知必然要对强连通分量进行缩点,缩点后变成了一个弱连通图。根据规则2、3可知即是要求图的最小路径覆盖。
定义:
最小路径覆盖:在图中找一些路径(路径数最少),使之覆盖了图中所有的顶点,且每个顶点有且仅和一条路径有关联。
最小顶点覆盖:在图中找一些点(顶点数最少),使之覆盖了图中所有的边,每条边至少和一个顶点有关联。
二分图:最小顶点覆盖=最大匹配数。
最小路径覆盖=顶点数-最大匹配数。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 #include <cstring> 6 using namespace std; 7 8 const int maxn=55555; 9 int dfn[maxn], low[maxn], stack[maxn], belong[maxn], visit[maxn], match[maxn]; 10 bool instack[maxn]; 11 int top, scnt, Index, n, m, T; 12 vector<int>vt[maxn]; 13 14 struct Node 15 { 16 int u, v; 17 }f[2*maxn]; 18 19 void Init_tarjan() 20 { 21 top=scnt=Index=0; 22 for(int i=1; i<=n; i++) dfn[i]=low[i]=instack[i]=0; 23 } 24 25 void tarjan(int u) 26 { 27 stack[++top]=u; 28 dfn[u]=low[u]=++Index; 29 instack[u]=1; 30 for(int i=0; i<vt[u].size(); i++) 31 { 32 int v=vt[u][i]; 33 if(!dfn[v]) 34 { 35 tarjan(v); 36 low[u]=min(low[u],low[v]); 37 } 38 else if(instack[v]) 39 { 40 low[u]=min(low[u],dfn[v]); 41 } 42 } 43 if(low[u]==dfn[u]) 44 { 45 int v; 46 scnt++; 47 do 48 { 49 v=stack[top--]; 50 instack[v]=0; 51 belong[v]=scnt; 52 } 53 while(u!=v); 54 } 55 } 56 57 bool find(int u) 58 { 59 for(int i=0; i<vt[u].size(); i++) 60 { 61 int v=vt[u][i]; 62 if(!visit[v]) 63 { 64 visit[v]=1; 65 if(match[v]==-1||find(match[v])) 66 { 67 match[v]=u; 68 return true; 69 } 70 } 71 } 72 return false; 73 } 74 75 int hungary() 76 { 77 int cnt=0; 78 memset(match,-1,sizeof(match)); 79 for(int i=1; i<=scnt; i++) 80 { 81 for(int j=1; j<=scnt; j++) visit[j]=0; 82 if(find(i)) cnt++; 83 } 84 return cnt; 85 } 86 87 int main() 88 { 89 cin >> T; 90 while(T--) 91 { 92 cin >> n >> m; 93 for(int i=0; i<=n; i++) vt[i].clear(); 94 for(int i=0; i<m; i++) 95 { 96 scanf("%d%d",&f[i].u,&f[i].v); 97 vt[f[i].u].push_back(f[i].v); 98 } 99 Init_tarjan(); 100 for(int i=1; i<=n; i++) 101 if(!dfn[i]) tarjan(i); 102 for(int i=0; i<=n; i++) vt[i].clear(); 103 for(int i=0; i<m; i++) 104 { 105 int u=belong[f[i].u], v=belong[f[i].v]; 106 if(u==v) continue; 107 vt[u].push_back(v); 108 } 109 int ans=hungary(); 110 cout << scnt-ans <<endl; 111 } 112 return 0; 113 } 114 115 /* 116 10 117 10 11 118 1 2 119 2 3 120 3 1 121 3 4 122 5 6 123 6 7 124 7 5 125 4 5 126 10 9 127 9 8 128 8 4 129 2 130 */