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

【BZOJ】2208 连通数

时间:2015-07-24 13:00:21      阅读:253      评论:0      收藏:0      [点我收藏+]

标签:连通性分析   图论   tarjan   搜索   bzoj   

【解析1】暴力dfs

[分析]
由于数据范围N<=2000不大,所以尝试着O(N^2)暴力。
结果第一次由于空间只开了2000就直接爆了,然后还用了邻接矩阵也挂了,第三次才AC。
我已经弱得无话可说了...

[小结]多用邻接矩阵。

[代码]
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

const int N=2001;

struct G
{
	int v,nxt;
}map[N*N];
int tt,hd[N];
int n,v[N],res;

void dfs(int now)
{
	v[now]=1; res++;
	for (int k=hd[now];k;k=map[k].nxt)
		if (!v[map[k].v]) dfs(map[k].v);
}

inline void ins(int u,int v)
{
	map[++tt].v=v;
	map[tt].nxt=hd[u];
	hd[u]=tt;
}

int main(void)
{
	char c;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("\n");
		for (int j=1;j<=n;j++)
		{
			scanf("%c",&c);
			if (c=='1') ins(i,j);
		}
	}
	
	for (int i=1;i<=n;i++)
	{
		memset(v,0,sizeof v);
		dfs(i);
	}
	printf("%d\n",res);
	
	return 0;
}


【解析2】Tarjan+拓扑+状态压缩+dp

[分析]Tarjan缩点+拓扑+状态压缩统计答案。

[特别提醒]bitset存储的是原来的状态而不是染色的状态。

[吐槽]
bitset存了染色的状态然后无尽的WA。
也是因为对拍头一次写错了QAQ。

[小结]
①连通点对或非连通点对的求法:
[1]直接dfs
[2]Tarjan缩点,拓扑,割点一类的。
[3]分类讨论+代数变形,如[NOIP]2014某题。
②连通性分析
③bitset的使用方法

[代码]
/**************************************************************
    Problem: 2208
    User: y20070316
    Language: C++
    Result: Accepted
    Time:2636 ms
    Memory:73012 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
using namespace std;
 
const int N=2140;
 
struct G
{
    int v,nxt;
}map[N*N];
int hd[N],tt;   //Graph
int n;  //Basic
int dfn[N],pre[N],v[N],ct;
int stk[N],color[N],cnt[N],cc;  //Tarjan
G mapc[N*N];
int hdc[N],tc;  //SCC Graph
bitset <N> b[N];
int res,f[N];
int q[N],h,t,d[N];  //Topo+dp
 
inline void ins(int u,int v)
{
    map[++tt].v=v;
    map[tt].nxt=hd[u];
    hd[u]=tt;
}
 
void init(void)
{
    char c;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("\n");
        for (int j=1;j<=n;j++)
        {
            scanf("%c",&c);
            if (c=='1') ins(i,j);
        }
    }
}
 
inline int min(int i,int j)
{
    return i<j?i:j;
}
 
void tarjan(int now)
{
    pre[now]=dfn[now]=++ct;
    stk[++stk[0]]=now; v[now]=1;
    for (int k=hd[now];k;k=map[k].nxt)
    {
        if (v[map[k].v]==2) continue;
        if (v[map[k].v]==1)
        {
            dfn[now]=min(dfn[now],pre[map[k].v]);
            continue;
        }
        tarjan(map[k].v);
        dfn[now]=min(dfn[now],dfn[map[k].v]);
    }
    if (pre[now]==dfn[now])
    {
        cc++;
        for (;stk[stk[0]]^now;stk[0]--)
        {
            color[stk[stk[0]]]=cc;
            v[stk[stk[0]]]=2;
            cnt[cc]++;
            b[cc][stk[stk[0]]]=1;
            stk[stk[0]]=0;
        }
        color[stk[stk[0]]]=cc;
        v[stk[stk[0]]]=2;
        b[cc][stk[stk[0]]]=1;
        cnt[cc]++; stk[stk[0]--]=0;
    }
}
 
inline void insc(int u,int v)
{
    mapc[++tc].v=v;
    mapc[tc].nxt=hdc[u];
    hdc[u]=tc;
}
 
void build(void)
{
    for (int i=1;i<=n;i++)
        if (!v[i]) tarjan(i);
         
    for (int i=1;i<=n;i++)
        for (int k=hd[i];k;k=map[k].nxt)
            if (color[i]^color[map[k].v])
            {
                d[color[map[k].v]]++;
                insc(color[i],color[map[k].v]);
            }
}
 
void topo(void)
{
    int now;
    for (int i=1;i<=cc;i++)
        if (!d[i]) q[++t]=i;
    for (;h^t;)
    {
        now=q[++h];
        for (int k=hdc[now];k;k=mapc[k].nxt)
        {
            d[mapc[k].v]--;
            if (!d[mapc[k].v]) q[++t]=mapc[k].v;
        }
    }
     
    bitset<N> tmp;
    for (int i=cc;i;i--)
    {
        tmp.reset();
        res+=cnt[q[i]]*cnt[q[i]];
        for (int k=hdc[q[i]];k;k=mapc[k].nxt)
            tmp|=b[mapc[k].v];
        res+=cnt[q[i]]*tmp.count();
        b[q[i]]|=tmp;
    }
    printf("%d\n",res);
     
/*
    for (int i=1;i<=cc;i++) b[i][i]=true;
    for (int i=1;i<=cc;i++)
    {
        res+=cnt[i]*cnt[i];
        bitset<N> tmp;
        for (int j=1;j<=n;j++)
            if (color[j]==i)
                for (int k=hd[j];k;k=map[k].nxt)
                    tmp|=b[map[k].v];
        res+=cnt[i]*tmp.count();
        b[i]|=tmp;
    }
    printf("%d\n",res);
*/
}
 
int main(void)
{
    init();
    build();
    topo();
     
    return 0;
}


【解析3】Tarjan缩点+状压+dp

[分析]
仔细想想,Tarjan出来的编号不是已经满足拓扑序了吗......
直接状压+dp不行么? O__O "…

[小结]Tarjan直接求出SCC的拓扑序。

[代码]
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
using namespace std;

const int N=2140;

struct G
{
	int v,nxt;
}map[N*N];
int hd[N],tt;	//Graph
int n;	//Basic
int dfn[N],pre[N],v[N],ct;
int stk[N],color[N],cnt[N],cc;	//Tarjan
G mapc[N*N];
int hdc[N],tc;	//SCC Graph
bitset <N> b[N];
int res,f[N];
int q[N],h,t,d[N];	//Topo+dp

inline void ins(int u,int v)
{
	map[++tt].v=v;
	map[tt].nxt=hd[u];
	hd[u]=tt;
}

void init(void)
{
	char c;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("\n");
		for (int j=1;j<=n;j++)
		{
			scanf("%c",&c);
			if (c=='1') ins(i,j);
		}
	}
}

inline int min(int i,int j)
{
	return i<j?i:j;
}

void tarjan(int now)
{
	pre[now]=dfn[now]=++ct;
	stk[++stk[0]]=now; v[now]=1;
	for (int k=hd[now];k;k=map[k].nxt)
	{
		if (v[map[k].v]==2) continue;
		if (v[map[k].v]==1)
		{
			dfn[now]=min(dfn[now],pre[map[k].v]);
			continue;
		}
		tarjan(map[k].v);
		dfn[now]=min(dfn[now],dfn[map[k].v]);
	}
	if (pre[now]==dfn[now])
	{
		cc++;
		for (;stk[stk[0]]^now;stk[0]--)
		{
			color[stk[stk[0]]]=cc;
			v[stk[stk[0]]]=2;
			cnt[cc]++;
			b[cc][stk[stk[0]]]=1;
			stk[stk[0]]=0;
		}
		color[stk[stk[0]]]=cc;
		v[stk[stk[0]]]=2;
		b[cc][stk[stk[0]]]=1;
		cnt[cc]++; stk[stk[0]--]=0;
	}
}

inline void insc(int u,int v)
{
	mapc[++tc].v=v;
	mapc[tc].nxt=hdc[u];
	hdc[u]=tc;
}

void build(void)
{
	for (int i=1;i<=n;i++)
		if (!v[i]) tarjan(i);
		
	for (int i=1;i<=n;i++)
		for (int k=hd[i];k;k=map[k].nxt)
			if (color[i]^color[map[k].v])
			{
				d[color[map[k].v]]++;
				insc(color[i],color[map[k].v]);
			}
}

void topo(void)
{
	bitset<N> tmp;
	for (int i=1;i<=cc;i++)
	{
		res+=cnt[i]*cnt[i];
		tmp.reset();
		for (int k=hdc[i];k;k=mapc[k].nxt)
			tmp|=b[mapc[k].v];
		res+=cnt[i]*tmp.count();
		b[i]|=tmp;
	}
	printf("%d\n",res);
}

int main(void)
{	
	init();
	build();
	topo();
	
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【BZOJ】2208 连通数

标签:连通性分析   图论   tarjan   搜索   bzoj   

原文地址:http://blog.csdn.net/u013598409/article/details/47037499

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