tarjan代码

还有五天就是NOP2018了……本蒟蒻还要复习期中考试,因此实在没有时间写博客了(各种找借口)。这里就放一下代码

//Tarjan缩点
//题目描述:给一个有向图。每个点有一个权值,求权值和最大的路径的权值和
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
#define MAXN 10005
#define MAXM 100005
using namespace std;

inline int read()
{
    int f=1,x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

int n,m;
int cnt,num,tot,ans;
int u[MAXM],v[MAXM],head[MAXN],nxt[MAXM];//邻接表部分 
int dfn[MAXN],low[MAXN];//tarjan部分 
bool book[MAXN];
stack <int> s;
int p[MAXN],sd[MAXN],in_d[MAXN],dis[MAXN];//缩点+拓扑部分 
queue <int> q;

void add(int x,int y)
{
    u[++cnt]=x;//存起点以供后续重新建图使用 
    v[cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;
}

void tarjan(int x)
{
    dfn[x]=low[x]=++num;
    book[x]=1;
    s.push(x);
    for(int i=head[x];i;i=nxt[i])//标准tarjan 
    {
        int t=v[i];
        if(!dfn[t])
        {
            tarjan(t);
            low[x]=min(low[x],low[t]);
        }
        else if(book[t])
            low[x]=min(low[x],dfn[t]);
    }
    if(low[x]==dfn[x])
    {
        tot++;
        while(s.top()!=x)
        {
            int y=s.top();
            book[y]=0;
            p[x]+=p[y];//缩点的权值 
            sd[y]=x;//缩点标记 
            s.pop();
        }
        book[x]=0;
        sd[x]=x;
        s.pop();
    }
}

int main()
{
    int i;
    int x,y;
    n=read(); m=read();
    for(i=1;i<=n;i++) p[i]=read();
    for(i=1;i<=m;i++)
    {
        x=read();
        y=read();
        add(x,y);//有向图 
    }
    for(i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);

    memset(head,0,sizeof(head));
    memset(nxt,0,sizeof(nxt));
    for(i=1;i<=m;i++)//将缩后的点重新建图 
    {
        x=sd[u[i]],y=sd[v[i]];
        if(x!=y)
        {
            add(x,y);
            in_d[y]++;//每个点的入度(拓扑使用) 
        }
    }
    for(i=1;i<=n;i++)//利用拓扑搞dp,求最大权值路径 
    {
        if(sd[i]==i && !in_d[i])
        {
            q.push(i);
            dis[i]=p[i];//记得要把自己开始时的权值设成点权 
        }
    }
    while(!q.empty())
    {
        int x=q.front(); q.pop();
        for(i=head[x];i;i=nxt[i])
        {
            int t=v[i];
            dis[t]=max(dis[t],dis[x]+p[t]);
            in_d[t]--;
            if(!in_d[t]) q.push(t);//入度等于零,根据拓扑,入队 
        }
    }
    for(i=1;i<=n;i++)
        ans=max(ans,dis[i]);
    printf("%d",ans);
    return 0;
}
    


//Tarjan求割点
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 20005
#define MAXM 200005
using namespace std;

inline int read()
{
    int f=1,x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

int n,m;
int cnt,num,ans;
int v[MAXM],head[MAXN],nxt[MAXM];
int dfn[MAXN],low[MAXN];
bool cut[MAXN];
int i,j;

void add(int a,int b)
{
    v[++cnt]=b;
    nxt[cnt]=head[a];
    head[a]=cnt;
}

void tarjan(int x,int fa)
{
    int Child=0;
    dfn[x]=low[x]=++num;
    for(int i=head[x];i;i=nxt[i])
    {
        int nx=v[i];
        if(!dfn[nx])
        {
            tarjan(nx,fa);
            low[x]=min(low[x],low[nx]);
            Child++;
            if(x!=fa && dfn[x]<=low[nx])
                cut[x]=1;
        }
        else low[x]=min(low[x],dfn[nx]); //这行不要写错
    }
    if(x==fa && Child>=2)
        cut[x]=1;
}

int main()
{
    int i;
    int a,b;
    n=read(); m=read();
    for(i=1;i<=m;i++)
    {
        a=read();
        b=read();
        add(a,b);
        add(b,a);
    }
    for(i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i,i);
    for(i=1;i<=n;i++)
        if(cut[i]) ans++;
    printf("%d\n",ans);
    for(i=1;i<=n;i++)
        if(cut[i])
            printf("%d ",i);
    return 0;
}

~NOIP2018 加油~

猜你喜欢

转载自www.cnblogs.com/llllllpppppp/p/9903998.html
今日推荐