您的位置:首页 > 其它

LA 3523 tarjian求双连通分量+二分判奇圈

2016-01-25 14:53 363 查看
白书上有详细解说

代码与书上有些不同,但核心是相通的

//LA 3523 点双连通+二分判奇圈
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include<stack>
#include <stack>
#define inf 0x3f3f3f3f
#define lowbit(x) ((x)&(-x))
#define maxn 1050
using namespace std;
int dfn[maxn],low[maxn],n,m,head[maxn],cnt,cntt,belong[maxn],ans,block,color[maxn],e[maxn][maxn],iscut[maxn],in[maxn];
vector<int> blo[maxn];
struct ee
{
int next,to,fa;
}eage[maxn*maxn*2];
stack<ee> s;

void add(int a,int b)
{
eage[cntt].to=b;
//eage[cntt].w=c;
eage[cntt].next=head[a];
eage[cntt].fa=a;
head[a]=cntt++;
}

void init()
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(belong,0,sizeof(belong));
memset(iscut,0,sizeof(iscut));
memset(in,0,sizeof(in));
memset(e,0,sizeof(e));
cnt=cntt=0;
ans=0;
block=0;
while(!s.empty())
s.pop();
for(int i=0;i<=n;i++)
blo[i].clear();
}

void tarjian(int a,int b)
{
dfn[a]=low[a]=++cnt;
int child=0;
for(int i=head[a];i!=-1;i=eage[i].next)
{
int j=eage[i].to;
if(j==b)
continue;
if(!dfn[j])
{
s.push(eage[i]);
child++;
tarjian(j,a);
low[a]=min(low[j],low[a]);
if(low[j]>=dfn[a])
{
block++;
iscut[a]=1;
while(1)
{
ee x=s.top();
s.pop();
if(belong[x.fa]!=block)
{
belong[x.fa]=block;
blo[block].push_back(x.fa);
}
if(belong[x.to]!=block)
{
belong[x.to]=block;
blo[block].push_back(x.to);
}
if(x.fa==a&&x.to==j)
break;
}
}
}
else if(dfn[j]<dfn[a]) //这个很关键如果不这样的话,s中会加两次回边。
{s.push(eage[i]);low[a]=min(low[a],dfn[j]);}
}
if(b<0&&child==1)
iscut[a]=0;
}

bool twojudge(int a,int b)
{
for(int i=head[a];i!=-1;i=eage[i].next)
{
int j=eage[i].to;
if(belong[j]==b)
{
if(color[j]==color[a])
return false;
if(!color[j])
{
color[j]=3-color[a];
if(!twojudge(j,b))
return false;
}
}
}
return true;
}

int main () {
//freopen("d:\\in.txt","r",stdin);
while(~scanf("%d%d",&n,&m)&&(n+m))
{
init();
if(n==0&&m==0)
break;
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
e[a][b]=1;
e[b][a]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(!e[i][j]&&j!=i)
{
add(i,j);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjian(i,-1);
}
}
for(int i=1;i<=block;i++)
{
memset(color,0,sizeof(color)); //由于割点会重复,所以要清空。
for(int j=0;j<blo[i].size();j++)
belong[blo[i][j]]=i;
int u=blo[i][0];
color[u]=1;
if(!twojudge(u,i))
{
for(int j=0;j<blo[i].size();j++)
in[blo[i][j]]=1;
}
}
ans=n;
for(int i=1;i<=n;i++)
if(in[i])
ans--;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: