UVA 10972 RevolC FaeLoN(边连通分量)

时间:2023-03-10 05:26:34
UVA 10972 RevolC FaeLoN(边连通分量)

坑了我一天的题目。。跑了20ms挂了,就知道有个小毛病= =

无向图转有向图判强连通。

首先要知道什么样的无向图可以转化为强连通图?连通分量(环)自然是可以的;那么扩大范围(存在割顶),发现点连通分量也是可以的;再扩大范围(存在桥),明显不能满足。所以边连通分量是实现无向图与强连通图转化的界限。

那么如果原图本身不是边连通的呢?先缩点,问题转化为——怎样把无向无环图(森林)构建成边连通图:从度入手。其实真正要考虑的是叶子节点(degree==1),和部分根节点(degree==0或degree==1)。degree==0,需要加两条边;degree==1,一条;degree>=2,不需考虑。

注意:因为是有向边建图,每条边会加两次,所以s/2;但这样考虑还不完整,要(s+1)/2,附上一组数据。

 #include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#define clr(a,m) memset(a,m,sizeof(a))
#define ref(i,a,b) for(int i=a;i<=b;i++)
using namespace std; const int MAXN=; struct Edge{
int v,next,vis;
Edge(){}
Edge(int _v,int _next):v(_v),next(_next),vis(){}
}edge[MAXN*MAXN]; int head[MAXN],tol;
int low[MAXN],pre[MAXN],bccno[MAXN],bcc_cnt,dfs_clock;
int dg[MAXN]; stack<int>stk; void init()
{
tol=;
clr(head,-);
} void add(int u,int v)
{
edge[tol]=Edge(v,head[u]);
head[u]=tol++;
} void dfs(int u)
{
int v;
pre[u]=low[u]=++dfs_clock;
stk.push(u);
for(int i=head[u];i!=-;i=edge[i].next){
if(edge[i].vis)
continue;
edge[i].vis=edge[i^].vis=; v=edge[i].v;
if(!pre[v]){
dfs(v);
low[u]=min(low[u],low[v]);
}else if(!bccno[v])
low[u]=min(low[u],pre[v]);
}
if(pre[u]==low[u]){
bcc_cnt++;
do{
v=stk.top();
stk.pop();
bccno[v]=bcc_cnt;
}while(u!=v);
}
} void find_bcc(int n)
{
dfs_clock=bcc_cnt=;
memset(pre,,sizeof(pre));
memset(bccno,,sizeof(bccno)); ref(i,,n-)
if(!pre[i])
dfs(i);
} int main()
{
int n,m,u,v;
while(~scanf("%d%d",&n,&m))
{
init();
ref(i,,m-){
scanf("%d%d",&u,&v);
u--;v--;
add(u,v);
add(v,u);
}
find_bcc(n);
memset(dg,,sizeof(dg));
ref(i,,n-){
for(int j=head[i];j!=-;j=edge[j].next)
{
int v=edge[j].v;
if(bccno[i]!=bccno[v]){
dg[bccno[i]]++;
dg[bccno[v]]++;
}
}
}
int s=;
ref(i,,bcc_cnt){
if(dg[i]/==)
s+=;
else if(!dg[i])
s+=;
}
if(bcc_cnt==)printf("0\n");
else printf("%d\n",(s+)/);
}
return ;
}
/*
3 3
1 2 2 3 3 1 10 12
1 2
2 3
3 4
4 2
1 5
5 6
6 7
7 5
1 8
8 9
9 10
10 8
*/