码迷,mamicode.com
首页 > 其他好文 > 详细

hdu3861 强连通+最小路径覆盖

时间:2015-09-15 23:33:02      阅读:508      评论:0      收藏:0      [点我收藏+]

标签:

题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块;在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u;每个点都只能存在于单独一个块内。问最少需要划分多少块。

首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点。然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量。而这一条路径上的所有强连通分量就可以构成同一块。那么其实我们就是需要找出最少的这样的路径将所有点全部覆盖一遍,就是做一遍最小路径覆盖。

最小路径覆盖数=点数-拆点后的最大匹配数。

技术分享
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stack>
  4 #include<queue>
  5 using namespace std;
  6 
  7 const int maxn=10005;
  8 const int maxm=2e5+5;
  9 
 10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
 11 int n,t,scccnt;
 12 int stx[maxn],low[maxn],scc[maxn];
 13 int vis[maxn],match[maxn];
 14 stack<int>S;
 15 
 16 void init(){
 17     memset(head,-1,sizeof(head));
 18     size[0]=size[1]=0;
 19 }
 20 
 21 void add(int a,int b,int c=0){
 22     point[c][size[c]]=b;
 23     nxt[c][size[c]]=head[c][a];
 24     head[c][a]=size[c]++;
 25 }
 26 
 27 void dfs(int s){
 28     stx[s]=low[s]=++t;
 29     S.push(s);
 30     for(int i=head[0][s];~i;i=nxt[0][i]){
 31         int j=point[0][i];
 32         if(!stx[j]){
 33             dfs(j);
 34             low[s]=min(low[s],low[j]);
 35         }
 36         else if(!scc[j]){
 37             low[s]=min(low[s],stx[j]);
 38         }
 39     }
 40     if(low[s]==stx[s]){
 41         scccnt++;
 42         while(1){
 43             int u=S.top();S.pop();
 44             scc[u]=scccnt;
 45             if(s==u)break;
 46         }
 47     }
 48 }
 49 
 50 void setscc(){
 51     memset(stx,0,sizeof(stx));
 52     memset(scc,0,sizeof(scc));
 53     t=scccnt=0;
 54     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
 55     for(int i=1;i<=n;++i){
 56         for(int j=head[0][i];~j;j=nxt[0][j]){
 57             int k=point[0][j];
 58             if(scc[i]!=scc[k]){    
 59                 add(scc[i],scc[k]+scccnt,1);
 60             }
 61         }
 62     }
 63 }
 64 
 65 int dfs1(int k){
 66     for(int i=head[1][k];~i;i=nxt[1][i]){
 67         if(!vis[point[1][i]]){
 68             int p=point[1][i];
 69             vis[p]=1;
 70             if(match[p]==-1||dfs1(match[p])){
 71                 match[p]=k;
 72                 return 1;
 73             }
 74         }
 75     }
 76     return 0;
 77 }
 78 
 79 
 80 int main(){
 81     int T;
 82     scanf("%d",&T);
 83     while(T--){
 84         int m;
 85         scanf("%d%d",&n,&m);
 86         init();
 87         while(m--){
 88             int a,b;
 89             scanf("%d%d",&a,&b);
 90             add(a,b);
 91         }
 92         setscc();
 93         int ans=0;
 94         memset(match,-1,sizeof(match));
 95         for(int i=1;i<=2*scccnt;++i){
 96             memset(vis,0,sizeof(vis));
 97             if(dfs1(i)==1)ans++;
 98         }
 99         printf("%d\n",scccnt-ans);
100     }
101     return 0;
102 }
View Code

 

hdu3861 强连通+最小路径覆盖

标签:

原文地址:http://www.cnblogs.com/cenariusxz/p/4811732.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!