tarjan一直是我看了头大的问题,省选之前还是得好好系统的学习一下。我按照不同的算法在hdu上选题练习了一下,至少还是有了初步的认识。tarjan嘛,就是维护一个dfsnum[]和一个low[],在dfs树上处理图的连通性等问题。细节处的不同导致算法本身的不同作用。
有向图强连通缩点:大体思路是维护一个栈,满足访问一个点就push到栈里面,当满足low[now]==dfn[now]时出栈,用dfn[]更新low[]当且仅当下一个点在栈内(注意不是递归栈)。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 2200 #define MAXV MAXN #define MAXE MAXV*2 #define INF 0x3f3f3f3f struct Edge { int np; Edge *next; }E[MAXE],*V[MAXV]; int tope=-1; void addedge(int x,int y) { E[++tope].np=y; E[tope].next=V[x]; V[x]=&E[tope]; } int status[MAXN]; int stack[MAXN],tops=-1; int low[MAXN],dfn[MAXN],dfstime; int top[MAXN]; void tarjan(int now) { status[now]=1; stack[++tops]=now; low[now]=dfn[now]=++dfstime; Edge *ne; for (ne=V[now];ne;ne=ne->next) { if (status[ne->np]==1) { low[now]=min(low[now],dfn[ne->np]); }else if (status[ne->np]==0) { tarjan(ne->np); low[now]=min(low[now],low[ne->np]); } } if (low[now]==dfn[now]) { while (stack[tops]!=now) { status[stack[tops]]=2; top[stack[tops--]]=now; } status[stack[tops]]=2; top[stack[tops--]]=now; } //status[now]=2; } int a[MAXN]; int el[MAXE][2]; int degi[MAXN]; int cirv[MAXN]; int main() { freopen("input.txt","r",stdin); int n,m,x,y,z; while (~scanf("%d%d",&n,&m)) { for (int i=1;i<=n;i++) scanf("%d",a+i); for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); addedge(x,y); el[i][0]=x; el[i][1]=y; } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); for (int i=1;i<=m;i++) { if (top[el[i][0]]!=top[el[i][1]]) degi[top[el[i][1]]]++; } memset(cirv,INF,sizeof(cirv[0])*(n+10)); for (int i=1;i<=n;i++) cirv[top[i]]=min(cirv[top[i]],a[i]); int ans2=0,ans1=0; for (int i=1;i<=n;i++) { if (top[i]==i && !degi[top[i]]) { ans1++; ans2+=cirv[top[i]]; } } printf("%d %d\n",ans1,ans2); memset(V,0,sizeof(V[0])*(n+10)); memset(dfn,0,sizeof(dfn[0])*(n+10)); memset(degi,0,sizeof(degi[0])*(n+10)); memset(status,0,sizeof(status[0])*(n+10)); tope=-1; dfstime=0; } }