http://acm.hdu.edu.cn/showproblem.php?pid=3861
题意:
国王要对n个城市进行规划,将这些城市分成若干个城市,强连通的城市必须处于一个州,另外一个州内的任意两个城市u,v,有从u到v的路径或从v到u的路径。求最少可以分成几个州。
思路:
这道题目挺好。
首先,强连通分量进行缩点,重新建图。
新建的图就是一个DAG图,接下来就转换成了最小路径覆盖问题。
最小路径覆盖就是用尽量少的不相交的简单路径覆盖DAG的所有顶点。每个顶点只属于一条路径,单个顶点也可以作为一条路径。
最小路径覆盖=结点总数-最大匹配。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 #include<cmath> 8 #include<stack> 9 using namespace std; 10 11 const int maxn=5000+5; 12 13 int n,m; 14 15 vector<int> G[maxn]; 16 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt; 17 stack<int> S; 18 19 vector<int> new_G[maxn]; 20 int vis[maxn]; 21 int match[maxn]; 22 23 void dfs(int u) { 24 pre[u] = lowlink[u] = ++dfs_clock; 25 S.push(u); 26 for (int i = 0; i < G[u].size(); i++) 27 { 28 int v = G[u][i]; 29 if (!pre[v]) 30 { 31 dfs(v); 32 lowlink[u] = min(lowlink[u], lowlink[v]); 33 } 34 else if(!sccno[v]) 35 lowlink[u] = min(lowlink[u], pre[v]); 36 } 37 if (pre[u] == lowlink[u]) 38 { 39 scc_cnt++; 40 for(;;) 41 { 42 int x = S.top(); S.pop(); 43 sccno[x] = scc_cnt; 44 if (x == u) break; 45 } 46 } 47 } 48 49 void find_scc(int n) 50 { 51 dfs_clock = scc_cnt = 0; 52 memset(pre, 0, sizeof(pre)); 53 memset(sccno, 0, sizeof(sccno)); 54 for (int i = 1; i <= n; i++) 55 if (!pre[i]) dfs(i); 56 } 57 58 59 int match_dfs(int x) 60 { 61 for(int i=0;i<new_G[x].size();i++) 62 { 63 int v=new_G[x][i]; 64 if(!vis[v]) 65 { 66 vis[v]=1; 67 if(match[v]==-1 || match_dfs(match[v])) 68 { 69 match[v]=x; 70 return 1; 71 } 72 } 73 } 74 return 0; 75 } 76 77 int main() 78 { 79 //freopen("D:\input.txt","r",stdin); 80 int T; 81 scanf("%d",&T); 82 while(T--) 83 { 84 scanf("%d%d",&n,&m); 85 for(int i=1;i<=n;i++) G[i].clear(); 86 while(m--) 87 { 88 int u,v; 89 scanf("%d%d",&u,&v); 90 G[u].push_back(v); 91 } 92 find_scc(n); 93 for(int i=1;i<=scc_cnt;i++) new_G[i].clear(); 94 for(int u=1;u<=n;u++) 95 { 96 for(int i=0;i<G[u].size();i++) 97 { 98 int v=G[u][i]; 99 if(sccno[u]!=sccno[v]) new_G[sccno[u]].push_back(sccno[v]); 100 } 101 } 102 103 int tot=0; 104 memset(match,-1,sizeof(match)); 105 for(int i=1;i<=scc_cnt;i++) 106 { 107 memset(vis,0,sizeof(vis)); 108 tot+=match_dfs(i); 109 } 110 111 printf("%d ",scc_cnt-tot); 112 } 113 return 0; 114 }