hdu3861 强连通+最小路径覆盖
2015-09-15 22:35
99 查看
题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块;在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u;每个点都只能存在于单独一个块内。问最少需要划分多少块。
首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点。然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量。而这一条路径上的所有强连通分量就可以构成同一块。那么其实我们就是需要找出最少的这样的路径将所有点全部覆盖一遍,就是做一遍最小路径覆盖。
最小路径覆盖数=点数-拆点后的最大匹配数。
View Code
首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点。然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量。而这一条路径上的所有强连通分量就可以构成同一块。那么其实我们就是需要找出最少的这样的路径将所有点全部覆盖一遍,就是做一遍最小路径覆盖。
最小路径覆盖数=点数-拆点后的最大匹配数。
#include<stdio.h> #include<string.h> #include<stack> #include<queue> using namespace std; const int maxn=10005; const int maxm=2e5+5; int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2]; int n,t,scccnt; int stx[maxn],low[maxn],scc[maxn]; int vis[maxn],match[maxn]; stack<int>S; void init(){ memset(head,-1,sizeof(head)); size[0]=size[1]=0; } void add(int a,int b,int c=0){ point[c][size[c]]=b; nxt[c][size[c]]=head[c][a]; head[c][a]=size[c]++; } void dfs(int s){ stx[s]=low[s]=++t; S.push(s); for(int i=head[0][s];~i;i=nxt[0][i]){ int j=point[0][i]; if(!stx[j]){ dfs(j); low[s]=min(low[s],low[j]); } else if(!scc[j]){ low[s]=min(low[s],stx[j]); } } if(low[s]==stx[s]){ scccnt++; while(1){ int u=S.top();S.pop(); scc[u]=scccnt; if(s==u)break; } } } void setscc(){ memset(stx,0,sizeof(stx)); memset(scc,0,sizeof(scc)); t=scccnt=0; for(int i=1;i<=n;++i)if(!stx[i])dfs(i); for(int i=1;i<=n;++i){ for(int j=head[0][i];~j;j=nxt[0][j]){ int k=point[0][j]; if(scc[i]!=scc[k]){ add(scc[i],scc[k]+scccnt,1); } } } } int dfs1(int k){ for(int i=head[1][k];~i;i=nxt[1][i]){ if(!vis[point[1][i]]){ int p=point[1][i]; vis[p]=1; if(match[p]==-1||dfs1(match[p])){ match[p]=k; return 1; } } } return 0; } int main(){ int T; scanf("%d",&T); while(T--){ int m; scanf("%d%d",&n,&m); init(); while(m--){ int a,b; scanf("%d%d",&a,&b); add(a,b); } setscc(); int ans=0; memset(match,-1,sizeof(match)); for(int i=1;i<=2*scccnt;++i){ memset(vis,0,sizeof(vis)); if(dfs1(i)==1)ans++; } printf("%d\n",scccnt-ans); } return 0; }
View Code
相关文章推荐
- 面试记录
- 函数参数的三种传值方式
- 今天碰到一个骗子
- 三段话理解重载,覆盖,隐藏
- IO读取本地相关类fileinputstream(2015年9月14日)
- Android 多媒体应用——SoundPool音频播放
- 三段话理解重载,覆盖,隐藏
- 随笔
- android中如何使用一张图片适配不同尺寸的APP引导页
- HDU 1028
- 关于JSDoc插件
- IOS动画实现(2)ImageView自带动画
- 女人穿衣的20条基本法则
- 【学习日记】java网络编程知识点总结
- ACM大数相减
- 前台分页,感觉一般还能优化
- Codeforces Round #311 (Div. 2)
- iOS开发:如何给UIViewController瘦身
- RevitAPI: 如何使用API创建墙饰条
- MFC六大关键技术