本题是个有关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; }