kuangbin专题九 UVA315(无向图求割点算法模板)

题解:
这道题的输入有点恶心,我是看的别人弄的,这是一道求割点的模板题,套模板就行了。但是我有一件事情不明白,为什么是关心v和pre呢?关心v是否连接到u的父亲pre呢?那要是连接到u的爷爷或者祖先呢?怎么办?求大佬解答。不懂的话可以去看看这位大佬的博客:
http://blog.csdn.net/wtyvhreal/article/details/43530613
题外话:
要是我啥时候能自己弄一篇解释算法就厉害了ORZ。。。

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN=110;
vector<int>map[MAXN];
int low[MAXN];
int dfn[MAXN];
int stack[MAXN],head;
int belong[MAXN]; 
bool instack[MAXN];
bool cut[MAXN];//割边
int bridge;//割边(桥) 
int Index,sig;//这狗血的编译器不能编译index,index好像在UVA中有意义。。。MD 
int n,m;
void init()
{
    memset(low,0,sizeof(low));
    memset(belong,0,sizeof(belong));
    memset(dfn,-1,sizeof(dfn));
    memset(stack,0,sizeof(stack));
    memset(instack,false,sizeof(instack));
    memset(cut,false,sizeof(cut));
    for(int i=0;i<=n;i++) map[i].clear();
    Index=1;
    sig=0;
    head=0;
}
void Tarjan(int u,int pre)
{
    low[u]=dfn[u]=Index;
    Index++;
    stack[++head]=u;
    instack[u]=true;
    int son=0;
    for(int i=0;i<map[u].size();i++)
    {
        int v=map[u][i];
        if(dfn[v]==-1)
        {
            son++;
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);

            //桥
            //一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)。  
            if(low[v]>dfn[u])
            {
                bridge++;
            }

            //割点
            //一个顶点u是割点,当且仅当满足(1)或(2) 
            //(1) u为树根,且u有多于一个子树。
            //(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,
            //即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)    
            if(u!=pre&&low[v]>=dfn[u])
            {
                cut[u]=true;
            }
        }
        else if(v!=pre)//这里一定要有v!=pre,代表的是v不能回溯到u的父亲节点。(但是我有一事不明,为什么是只关心他的父亲呢,他的爷爷,他祖先不用管理吗?要是连到他的爷爷或者祖先节点呢?希望有dalao解答) 
        {
//还有就是我用instack[v]&&v!=pre也是可以的,我还是不明白上面那行说的情况啊,ORZ
            low[u]=min(low[u],dfn[v]);
        }
    }
    //树根,分支数大于1的也算是割点
    if(u==pre&&son>1) cut[u]=true; 
    if(low[u]==dfn[u])
    {
        int temp;
        sig++;
        while(1)
        {
            temp=stack[head--];
            belong[temp]=sig;
            instack[temp]=false;
            if(temp==u)
            break;
        }
    }
}
void solve()
{
    bridge=0;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(dfn[i]==-1)
        Tarjan(i,i);
    }
    for(int i=1;i<=n;i++)
    if(cut[i])
    ans++;
    printf("%d\n",ans);
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        init();
        int u,v;
        char c;
        while(~scanf("%d",&u)&&u)
        {
            while(~scanf("%d%c",&v,&c))
            {
                map[u].push_back(v);
                map[v].push_back(u);
                if(c=='\n')
                break;
            }
        }
        solve();
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值