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;
}
代码与书上有些不同,但核心是相通的
//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;
}
相关文章推荐
- jQuery中inArray方法注意事项分析
- 沉湎网络 心理障碍
- leetcode之Add Binary
- 自动生成android、ios开发所需要的所有尺寸的图片
- cocos2d-x3.2中加入Android手机震动
- 3D文字菜单变换
- 解决android studio设置版本号
- C++ template —— 模板特化(五)
- ---------很简单的 一道 堆栈问题-------
- linux 乱码问题解决
- PtrClassicFrameLayout 下拉刷新控件
- Android之数据持久化三(sqllite数据库)三
- GitHub 优秀的 Android 开源项目
- poj 1958 Strange Towers of Hanoi
- SQLITE3 使用总结(转)
- svn提交失败: Checksum mismatch for(转)
- R语言做文本挖掘 Part1安装依赖包
- Scala 入门——Eclipse开发环境搭建
- hibernate--链接数据源C3P0
- SLF4JLoggerContext cannot be cast to LoggerContext