首页 > 其他 > 详细

tarjan 求缩点

时间:2021-05-28 22:40:28      阅读:30      评论:0      收藏:0      [点我收藏+]

给定一个 nn 个点 mm 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

第一行两个正整数 n,mn,m

第二行 nn 个整数,依次代表点权

第三至 m+2m+2 行,每行两个整数 u,vu,v,表示一条 u\rightarrow vuv 的有向边。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=10005;
ll n,m,sum,tim,top,s;
ll p[maxn],head[maxn],sd[maxn],dfn[maxn],low[maxn];
ll stac[maxn],vis[maxn];
ll h[maxn],in[maxn],dist[maxn];
struct st {
    int to;
    int next;
    int from;
}edge[maxn*10],ed[maxn*10];
void add(int x,int y){
    edge[++sum].next=head[x];
    edge[sum].from=x;
    edge[sum].to=y;
    head[x]=sum;
}
void tarjan(int x){
    low[x]=dfn[x]=++tim;
    stac[++top]=x;
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        int v=edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v]){
            low[x]=min(low[x],low[v]);    
        }
    }
    if(dfn[x]==low[x]){
        int y;
        while(y=stac[top--]){
            sd[y]=x;
            vis[y]=0;
            if(x==y){
                break;
            }
            p[x]+=p[y];
        }
    }
}
ll topo(){
    queue<int >q;
    int tot=0;
    for(int i=1;i<=n;i++){
        if(sd[i]==i&&!in[i]){
            q.push(i);
            dist[i]=p[i];
        }
    }
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        for(int i=h[temp];i;i=ed[i].next){
            int v=ed[i].to;
            dist[v]=max(dist[v],dist[temp]+p[v]);
            in[v]--;
            if(in[v]==0)q.push(v);
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dist[i]);
    }
    return ans;
}
void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>p[i];
    for(int i=1;i<=m;i++){
        ll u,v;
        cin>>u>>v;
        add(u,v);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    for(int i=1;i<=m;i++){
        int x=sd[edge[i].from],y=sd[edge[i].to];
        if(x!=y){
            ed[++s].next=h[x];
            ed[s].to=y;
            ed[s].from=x;
            h[x]=s;
            in[y]++;
        }
    }
    cout<<topo()<<endl;
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
//    freopen("1.in","r",stdin);
//    getlist(1e7);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
    
}

 

tarjan 求缩点

原文:https://www.cnblogs.com/LH2000/p/14823879.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!