首页 > 代码库 > HDU 3861 The King's Problem(强连通分量缩点+最小路径覆盖)

HDU 3861 The King's Problem(强连通分量缩点+最小路径覆盖)

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\n",scc_cnt-tot);112     }113     return 0;114 }

 

 

HDU 3861 The King's Problem(强连通分量缩点+最小路径覆盖)