洛谷P1262+Tarjan缩点

本题是个有关Tarjan的题。
首先我们来预习(温习)一下tarjan缩点:SCC是相互可达,先跑Tarjan然后建个新图。
洛谷板子:P3387

Code:

#include<iostream>
#include<cstdio>
#include<stack>
#include<queue>
#include<cstring>
#define INF 0x3f3f3f3f
#define ll long long
#define maxn 100001
using namespace std;
struct Edge{
    int nxt,to,dis;
}edge[maxn];
int n,m,low[maxn],dfn[maxn],a[maxn],tot[maxn],ans,num_edge,qaq[maxn],qwq[maxn],head[maxn],cnt,sccnum[maxn],vis[maxn],dis[maxn],scc_cnt;
stack<int> s;
inline void addedge(int from,int to){
    edge[++num_edge].nxt=head[from];
    edge[num_edge].to=to;
    head[from]=num_edge;
}
void tarjan(int x){
    dfn[x]=low[x]=++cnt;
    s.push(x);
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(!sccnum[y]){
            low[x]=min(dfn[y],low[x]);
        }
    }
    if(low[x]==dfn[x]){
        scc_cnt++;
        for(;;){
            //num[scc_cnt]++;
            int y=s.top();
            tot[scc_cnt]+=a[y];
            s.pop();
            sccnum[y]=scc_cnt;
            if(y==x) break;
        }
    }
}
inline void spfa(int s){
    queue<int> q;
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    vis[s]=1;
    dis[s]=tot[s];
    q.push(s);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(dis[y]<dis[x]+tot[y]){
                dis[y]=dis[x]+tot[y];
                if(vis[y]==0){
                    q.push(y);
                    vis[y]=1;
                }
            }
        }
    }
    for(int i=1;i<=scc_cnt;i++){
        ans=max(ans,dis[i]);
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        addedge(x,y);
        qwq[i]=x;
        qaq[i]=y;
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tarjan(i);
    }
    memset(edge,0,sizeof(edge));
    memset(head,0,sizeof(head));
    num_edge=0;
    for(int i=1;i<=m;i++){
        if(sccnum[qwq[i]]!=sccnum[qaq[i]]){
            addedge(sccnum[qwq[i]],sccnum[qaq[i]]);
        }
    }
    for(int i=1;i<=scc_cnt;i++){
        spfa(i);
    }
    cout<<ans;
    return 0;
}

我们再考虑间谍网络这个题。
统计一下入度,没了。
Code:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<stack>
#include<cmath>
#define ll long long
#define maxn 100001
#define INF 0x3f3f3f3f
using namespace std;
struct Edge{
    int nxt,to,dis;
}edge[maxn];
int n,m,low[maxn],dfn[maxn],rd[maxn],a[maxn],tot[maxn],ans,num_edge,qaq[maxn],qwq[maxn],head[maxn],cnt,sccnum[maxn],vis[maxn],dis[maxn],scc_cnt;
stack<int> s;
inline void addedge(int from,int to){
    edge[++num_edge].nxt=head[from];
    edge[num_edge].to=to;
    head[from]=num_edge;
}
void tarjan(int x){
    dfn[x]=low[x]=++cnt;
    s.push(x);
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(!sccnum[y]){
            low[x]=min(dfn[y],low[x]);
        }
    }
    if(low[x]==dfn[x]){
        scc_cnt++;
        for(;;){
            //num[scc_cnt]++;
            int y=s.top();
           // tot[scc_cnt]+=a[y];
            tot[scc_cnt]=min(tot[scc_cnt],a[y]);
            s.pop();
            sccnum[y]=scc_cnt;
            if(y==x) break;
        }
    }
}
int main(){
    memset(a,INF,sizeof(a));
    memset(tot,INF,sizeof(tot));
    int p,r;
    cin>>n>>p;
    for(int i=1;i<=p;i++){
       // int x,y;
        //cin>>x>>y;
        //addedge(x,y);
        //qwq[i]=x;
        //qaq[i]=y;
        int x,y;
        cin>>x>>y;
        a[x]=y;
    }
    cin>>r;
    for(int i=1;i<=r;i++){
        int x,y;
        cin>>x>>y;
        addedge(x,y);
    //    qwq[i]=x;
    //    qaq[i]=y;
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]&&a[i]!=INF) tarjan(i);
    }
  //  memset(edge,0,sizeof(edge));
  //  memset(head,0,sizeof(head));
   // num_edge=0;
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            cout<<"NO"<<endl;
            cout<<i<<endl;
            return 0;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=edge[j].nxt){
            if(sccnum[i]!=sccnum[edge[j].to]){
            rd[sccnum[edge[j].to]]++; 
        }
    }
   for(int i=1;i<=scc_cnt;i++){
       if(!rd[i]){
           ans+=tot[i];
       }
   }
   cout<<"YES"<<endl;
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kenlig/p/9822594.html