tarjan代码
还有五天就是NOIP2018了……本蒟蒻还要复习期中考试,因此实在没有时间写博客了(各种找借口)。这里就放一下代码
//Tarjan缩点 //题目描述:给一个有向图。每个点有一个权值,求权值和最大的路径的权值和 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<stack> #include<queue> #define MAXN 10005 #define MAXM 100005 using namespace std; inline int read() { int f=1,x=0; char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1; ch=getchar();} while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int n,m; int cnt,num,tot,ans; int u[MAXM],v[MAXM],head[MAXN],nxt[MAXM];//邻接表部分 int dfn[MAXN],low[MAXN];//tarjan部分 bool book[MAXN]; stack <int> s; int p[MAXN],sd[MAXN],in_d[MAXN],dis[MAXN];//缩点+拓扑部分 queue <int> q; void add(int x,int y) { u[++cnt]=x;//存起点以供后续重新建图使用 v[cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; } void tarjan(int x) { dfn[x]=low[x]=++num; book[x]=1; s.push(x); for(int i=head[x];i;i=nxt[i])//标准tarjan { int t=v[i]; if(!dfn[t]) { tarjan(t); low[x]=min(low[x],low[t]); } else if(book[t]) low[x]=min(low[x],dfn[t]); } if(low[x]==dfn[x]) { tot++; while(s.top()!=x) { int y=s.top(); book[y]=0; p[x]+=p[y];//缩点的权值 sd[y]=x;//缩点标记 s.pop(); } book[x]=0; sd[x]=x; s.pop(); } } int main() { int i; int x,y; n=read(); m=read(); for(i=1;i<=n;i++) p[i]=read(); for(i=1;i<=m;i++) { x=read(); y=read(); add(x,y);//有向图 } for(i=1;i<=n;i++) if(!dfn[i]) tarjan(i); memset(head,0,sizeof(head)); memset(nxt,0,sizeof(nxt)); for(i=1;i<=m;i++)//将缩后的点重新建图 { x=sd[u[i]],y=sd[v[i]]; if(x!=y) { add(x,y); in_d[y]++;//每个点的入度(拓扑使用) } } for(i=1;i<=n;i++)//利用拓扑搞dp,求最大权值路径 { if(sd[i]==i && !in_d[i]) { q.push(i); dis[i]=p[i];//记得要把自己开始时的权值设成点权 } } while(!q.empty()) { int x=q.front(); q.pop(); for(i=head[x];i;i=nxt[i]) { int t=v[i]; dis[t]=max(dis[t],dis[x]+p[t]); in_d[t]--; if(!in_d[t]) q.push(t);//入度等于零,根据拓扑,入队 } } for(i=1;i<=n;i++) ans=max(ans,dis[i]); printf("%d",ans); return 0; }
//Tarjan求割点 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define MAXN 20005 #define MAXM 200005 using namespace std; inline int read() { int f=1,x=0; char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1; ch=getchar();} while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int n,m; int cnt,num,ans; int v[MAXM],head[MAXN],nxt[MAXM]; int dfn[MAXN],low[MAXN]; bool cut[MAXN]; int i,j; void add(int a,int b) { v[++cnt]=b; nxt[cnt]=head[a]; head[a]=cnt; } void tarjan(int x,int fa) { int Child=0; dfn[x]=low[x]=++num; for(int i=head[x];i;i=nxt[i]) { int nx=v[i]; if(!dfn[nx]) { tarjan(nx,fa); low[x]=min(low[x],low[nx]); Child++; if(x!=fa && dfn[x]<=low[nx]) cut[x]=1; } else low[x]=min(low[x],dfn[nx]); //这行不要写错 } if(x==fa && Child>=2) cut[x]=1; } int main() { int i; int a,b; n=read(); m=read(); for(i=1;i<=m;i++) { a=read(); b=read(); add(a,b); add(b,a); } for(i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i); for(i=1;i<=n;i++) if(cut[i]) ans++; printf("%d\n",ans); for(i=1;i<=n;i++) if(cut[i]) printf("%d ",i); return 0; }
~NOIP2018 加油~