码迷,mamicode.com
首页 > Web开发 > 详细

bzoj2208: [Jsoi2010]连通数 缩点+拓扑+状压

时间:2016-05-15 21:31:18      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:

tarjan缩点后拓扑排序,每一个点用一个bitset记录哪些点能到达它。

PS:数据太水,暴力能过。

#include<bits/stdc++.h>
using namespace std;
#define N 2010
struct edge{
	edge* s;
	int v;
}e[N*N*2],*back=e,*h[N];
int low[N],num[N],scc[N],size[N];
int now;
void tarjan(int u){
	static int cnt;
	static stack<int> s;
	low[u]=num[u]=++cnt;
	s.push(u);
	for(edge* i=h[u];i;i=i->s)
		if(!num[i->v]){
			tarjan(i->v);
			low[u]=min(low[u],low[i->v]);
		}else if(!scc[i->v])
			low[u]=min(low[u],num[i->v]);
	if(low[u]==num[u]){
		static int v;
		++now;
		do{
			v=s.top();
			s.pop();
			++size[scc[v]=now];
		}while(u!=v);
	}
}
int main(){
	static char s[N+1];
	int n;
	scanf("%d",&n);
	for(int i=0;i!=n;++i){
		scanf("%s",s);
		for(int j=0;j!=n;++j)
			if(s[j]^48)
				h[i]=&(*back++=(edge){h[i],j});
	}
	for(int i=0;i!=n;++i)
		if(!num[i])
			tarjan(i);
	static bool v[N][N];
	for(int u=0;u!=n;++u)
		for(edge* i=h[u];i;i=i->s)
			v[scc[u]][scc[i->v]]=1;
	memset(h,0,sizeof h);
	static int in[N];
	for(int i=1;i<=now;++i)
		for(int j=1;j<=now;++j)
			if(i!=j&&v[i][j]){
				++in[j];
				h[i]=&(*back++=(edge){h[i],j});
			}
	static bitset<N> f[N];
	queue<int> q;
	for(int i=1;i<=now;++i){
		f[i][i]=1;
		if(!in[i])
			q.push(i);
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(edge* i=h[u];i;i=i->s){
			if(!--in[i->v])
				q.push(i->v);
			f[i->v]|=f[u];
		}
	}
	int ans=0;
	for(int i=1;i<=now;++i)
		for(int j=1;j<=now;++j)
			if(f[i][j])
				ans+=size[i]*size[j];
	printf("%d\n",ans);
}

  

bzoj2208: [Jsoi2010]连通数 缩点+拓扑+状压

标签:

原文地址:http://www.cnblogs.com/f321dd/p/5495997.html

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