【HDU3861 强连通分量缩点+二分图最小路径覆盖】

题目链接: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 */
View Code

 

 

 

posted @ 2013-07-21 17:16  Mr. Ant  阅读(1124)  评论(0编辑  收藏  举报