【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

 

 

 

你可能感兴趣的:(HDU)