Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 23843 | Accepted: 9779 |
Description
Input
Output
Sample Input
3 3 1 2 2 1 2 3
Sample Output
1
Hint
Source
题目大意:给有向图G,求图G中有多少点能从所有起点到达
暴搜必T,故本题需要用Tarjen求有向图的强连通分量。
缩点后得DAG(若有环则属同一强连通分量)
由于无环,故这图为树或树的森林
先判断图是否连通,若为森林则无解
否则,判定每个SSC是否有连出的边(由于图无环,故连出的边上的点无法回去)
答案即为出度为0的连通分量上的点
如果不止一个这样的点,则不同的点无法互相到达
Program P2186; const maxn=10000; maxm=50000; var head,edge,tail:array[1..maxm] of longint; sizeedge:longint; n,m,i,j,x,y:longint; ssc,c,dfs,low,outdegree,stack:array[1..maxn] of longint; time,size:longint; totssc:longint; procedure addedge(u,v:longint); begin inc(sizeedge); edge[sizeedge]:=v; tail[sizeedge]:=head[u]; head[u]:=sizeedge; end; function min(a,b:longint):longint; begin if a<b then exit(a) else exit(b); end; procedure tarjen(k,father:longint); var i,j,p:longint; begin inc(time); dfs[k]:=time;low[k]:=time; c[k]:=1; inc(size);stack[size]:=k; p:=head[k]; while (p<>0) do begin i:=edge[p]; if (dfs[k]>dfs[i]) then begin if c[i]=0 then begin tarjen(i,k); low[k]:=min(low[k],low[i]); end else if c[i]=1 then low[k]:=min(low[k],dfs[i]); end; p:=tail[p]; end; if low[k]=dfs[k] then begin inc(totssc); repeat i:=stack[size]; dec(size); c[i]:=2; ssc[i]:=totssc; until ((size=0) or (i=k)); end; end; function main:longint; var i,j,tot,node,p:longint; begin fillchar(dfs,sizeof(dfs),0); fillchar(low,sizeof(low),0); fillchar(c,sizeof(c),0); fillchar(outdegree,sizeof(outdegree),0); time:=0; totssc:=0; for i:=1 to n do if (dfs[i]=0) then begin fillchar(stack,sizeof(stack),0); size:=0; tarjen(i,0); end; for i:=1 to n do begin p:=head[i]; while (p<>0) do begin j:=edge[p]; if (ssc[i]<>ssc[j]) then begin inc(outdegree[ssc[i]]); end; p:=tail[p]; end; end; node:=0; for i:=1 to totssc do if outdegree[i]=0 then begin if node<>0 then exit(0); node:=i; end; tot:=0; for i:=1 to n do if ssc[i]=node then inc(tot); exit(tot); end; begin sizeedge:=0; fillchar(head,sizeof(head),0); fillchar(tail,sizeof(tail),0); fillchar(edge,sizeof(edge),0); read(n,m); for i:=1 to m do begin read(x,y); addedge(x,y); end; writeln(main); end.
现增加ACM,SSC(强连通分量/缩点)Template,撒花 Flower
再说一遍这个算法SSC(强连通分量/缩点):
1.dfs一遍,回溯前给顶点标号
2.把图中的边反向(记为rG),按照标号从小到大rdfs,每次dfs标号k(第k强连通分量)
PS:图中无环(DAG:有向无环图),后标号的点在早标号的点的后面(拓扑序)
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> #include<vector> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define ForD(i,n) for(int i=n;i;i--) #define RepD(i,n) for(int i=n;i>=0;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define Lson (x<<1) #define Rson ((x<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define MEMI(a) memset(a,127,sizeof(a)); #define MEMi(a) memset(a,128,sizeof(a)); #define INF (2139062143) #define F (100000007) #define MAXN (10000+10) #define MAXM (50000+10) long long mul(long long a,long long b){return (a*b)%F;} long long add(long long a,long long b){return (a+b)%F;} long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;} typedef long long ll; class SSC { public: int n,b[MAXN],num[MAXN]; vector<int> G[MAXN],rG[MAXN]; //图,反向后的图 vector<int> vs; //后续遍历顶点列表 void mem(int _n) { n=_n; MEM(num) For(i,n) G[i].clear(),rG[i].clear(); vs.clear(); } void addedge(int u,int v) { G[u].push_back(v); rG[v].push_back(u); } void dfs(int x) { b[x]=1; Rep(i,G[x].size()) { if (!b[G[x][i]]) dfs(G[x][i]); } vs.push_back(x); } void rdfs(int x,int k) { b[x]=1;num[x]=k; Rep(i,rG[x].size()) { if (!b[rG[x][i]]) rdfs(rG[x][i],k); } } int ssc() { MEM(b) For(i,n) if (!b[i]) dfs(i); MEM(b) int k=0; RepD(i,vs.size()-1) if (!b[vs[i]]) rdfs(vs[i],++k); return k; } }S; int n,m; int main() { // freopen("poj2186_template.in","r",stdin); // freopen(".out","w",stdout); cin>>n>>m; S.mem(n); For(i,m) { int u,v; scanf("%d%d",&u,&v); S.addedge(u,v); } int new_n=S.ssc(); int ans=0,x=0; For(i,n) if (S.num[i]==new_n) ans++,x=i; MEM(S.b) S.rdfs(x,-1); For(i,n) if (S.num[i]!=-1) {cout<<"0\n"; return 0;} cout<<ans<<endl; return 0; }