HDU 4694 Important Sisters Lengauer_Tarjan算法

8 篇文章 0 订阅

题目大意:给定一张 n 个点m条边的有向图,保证 n 号点可以到达所有点,求n号节点到每个点的必经点的编号之和

数据是错的,存在 n 号点无法到达的点,这些点输出0

求Dominator Tree的Lengauer-Tarjan算法,具体做法自己百度我不赘述了

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
using namespace std;

inline void Assert(bool flag)
{
    if(!flag) while(1) puts("233");
    //if(!flag) throw false;
}

struct abcd{
    int to,next;
}table[100100<<1];
int head[M],_head[M],tot;
void Add(int head[],int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}

int n,m;
long long ans[M];
int fa[M],dfn[M],identification[M],semi[M],idom[M],T;
vector<int> dom[M];

bool Compare(int x,int y)
{
    return dfn[semi[x]] < dfn[semi[y]] ;
}

namespace Union_Find_Set{
    int fa[M],best[M];
    void Initialize()
    {
        int i;
        for(i=1;i<=n;i++)
            fa[i]=best[i]=i;
    }
    int Find(int x)
    {
        if(fa[x]==x)
            return x;
        int p=Find(fa[x]);
        best[x]=min(best[x],best[fa[x]],Compare);
        return fa[x]=p;
    }
}

void Initialize()
{
    memset(head,0,sizeof head);
    memset(_head,0,sizeof _head);tot=0;
    memset(ans,0,sizeof ans);
    memset(fa,0,sizeof fa);
    memset(dfn,0,sizeof dfn);T=0;
    memset(identification,0,sizeof identification);
    memset(semi,0,sizeof semi);
    memset(idom,0,sizeof idom);
    Union_Find_Set::Initialize();
}

void DFS(int x)
{
    int i;
    identification[dfn[x]=++T]=x;
    for(i=head[x];i;i=table[i].next)
        if(!dfn[table[i].to])
            DFS(table[i].to),fa[table[i].to]=x;
}

void Lengauer_Tarjan()
{
    int i,j;
    DFS(n);
    dfn[0]=0x3f3f3f3f;
    //Assert(T==n);
    for(j=T;j;j--)
    {
        int x=identification[j];
        if(j!=1)
        {
            for(i=_head[x];i;i=table[i].next)
            {
                if(!dfn[table[i].to]) continue;
                if(dfn[table[i].to]>dfn[x])
                {
                    Union_Find_Set::Find(table[i].to);
                    if(dfn[semi[Union_Find_Set::best[table[i].to]]]<dfn[semi[x]])
                        semi[x]=semi[Union_Find_Set::best[table[i].to]];
                }
                else
                {
                    if(dfn[table[i].to]<dfn[semi[x]])
                        semi[x]=table[i].to;
                }
            }
            dom[semi[x]].push_back(x);
        }
        while(dom[x].size())
        {
            int y=dom[x].back();
            dom[x].pop_back();
            Union_Find_Set::Find(y);
            if(semi[Union_Find_Set::best[y]]!=x)
                idom[y]=Union_Find_Set::best[y];
            else
                idom[y]=x;
        }
        for(i=head[x];i;i=table[i].next)
            if(fa[table[i].to]==x)
                Union_Find_Set::fa[table[i].to]=x;
    }
    for(j=2;j<=T;j++)
    {
        int x=identification[j];
        if(idom[x]!=semi[x])
            idom[x]=idom[idom[x]];
    }
    idom[identification[1]]=0;
}

long long Get_Ans(int x)
{
    //Assert(x);
    if(x==n) return ans[x]=n;
    if(ans[x]) return ans[x];
    return ans[x]=Get_Ans(idom[x])+x;
}

int main()
{
    #ifdef PoPoQQQ
    freopen("4694.in","r",stdin);
    freopen("4694.out","w",stdout);
    #endif
    int i,x,y;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        Initialize();
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            Add(head,x,y);
            Add(_head,y,x);
        }
        Lengauer_Tarjan();
        for(i=1;i<=n;i++)
            printf("%I64d%c",dfn[i]?Get_Ans(i):0,i==n?'\n':' ');
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值