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
",scc_cnt-tot);
112     }
113     return 0;
114 }
 
原文地址:https://www.cnblogs.com/zyb993963526/p/6817075.html