Tarjan缩点

今天考的是APIO2009

然鹅我爆零了。。。

T1 MLE,T2没写,T3 RE+WA+TLE

T1 dp 写挂了,肝了2小时,以为自己写出来了,结果还是错了,而且还MLE了。所以洛谷测的20分,但是lemon上0分。

(洛谷还写的是宜参加模拟赛 我信你个鬼

T2 第一问比较水 但是第二问把我卡住了 (据ZZX巨佬所言,这题我们大约去年10月的时候考过,但是我完全没印象??! 我看了题解 感觉还是有点懵)

T3 其实是缩点裸题 奈何我永远不记得缩点怎么写了(之前写过,但是忘了,也没太在意) 每次考场上遇到只能自己瞎写了QAQ

鉴于以上教训

我决定 先恶补一发tarjan缩点 (我觉得我也要恶补图论 毕竟我的图论太烂了) 然后立个flag 如果有时间 一定要写一篇 APIO2009 的题解 

那么

进入正题吧!


 

先来一波定义~

有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量,简记为SCC。点击查看百度百科

流图:给定有向图G=(V,E),若存在r∈V,满足从r出发能够到达V中所有的点,则成G是一个“流图”,记为(G,r),其中r称为流图的源点。

时间戳对于一个流图(G,r),我们对它从r开始进行深度优先遍历,每个节点只访问一次,每个节点被访问的时间顺序(即该节点是第几个被访问),称为该节点的时间戳。

对于每一个节点,我们用dfn[i]记录它的时间戳,用low[i]记录它的回溯值(即不经过流图搜索树上该节点父亲能返回的最小的时间戳)。

对于一个节点u,设其子树(流图搜索树中)为subtree(u),我们也可以这样定义它的low值:

对于有向图中满足以下条件的节点中最小的dfn值:

① 存在一条从subtree(u)出发的路径,以该节点为终点;

②遍历到u的子树时,该节点还在栈中。

Tarjan缩点_第1张图片

 (②是为了避免图中这种情况的出现,图中节点编号也是节点的时间戳,栈中保留的节点应该是u的祖先节点及已经访问过且存在一条边到u的祖先节点的节点)

 

这样我们就可以求low值啦:

枚举u的每一条出边,设该边的终点为v

①若v已经访问过并v还在栈中 则直接low[u]=min(low[u],dfn[v])。

②若v还没访问过 就将v加入栈中 并将low[u]和low[v]取min。

最后 判断一下 dfn[u]是否等于low[u],

若相等 就直接弹出栈中的元素(弹到是u就停止),则这些元素构成一个强连通分量(有可能只有一个元素)。

相等说明 u子树内的顶点不可能与栈内u以前的节点构成一个环。

(自己手动模拟一下就明白啦~)

 1 void dfs(int po,int fa)
 2 {
 3     if(!dfn[po]) dfn[po]=low[po]=++tim;
 4     sta[++tl]=po,in[po]=1;//入栈
 5     vis[po]=1;
 6     for(int i=hd[po];i;i=e[i].n)
 7     {
 8         int v=e[i].v;
 9         if(vis[v]&&in[v]) low[po]=min(low[po],dfn[v]);//如果能回到比它时间戳更早的节点
10         else if(!vis[v]) //如果该节点还未访问过
11         {
12             dfs(v,po);
13             low[po]=min(low[po],low[v]);
14         }
15      } 
16     if(dfn[po]==low[po])//回溯前将栈内元素弹出
17     {
18         bool bb=0;
19         cnt++;
20         while(!bb){
21             if(sta[tl]==po) bb=1;
22             cir[sta[tl]]=cnt;
23             cw[cnt]+=w[sta[tl]];//此处 记录一个强连通分量内的节点的权值之和(后面板子题以及APIO2009T3要用到)
24             in[sta[tl]]=0;
25             sta[tl--]=0;
26         }
27     }
28 }

 以上就是求tarjan缩点的核心代码~

练习

1.一道板子题 

参考代码如下:

 1 #include 
 2 #include  
 3 #include 
 4 #define gc cr==cl&&(cr=(cl=bu)+fread(bu,1,100000,stdin),cl==cr)?EOF:*cl++
 5 #define gs (ch<'0'||ch>'9')
 6 #define r(x) x=read()
 7 using namespace std;
 8 const int N=1e4+111,M=1e5+111;
 9 int n,m,tot,cnt,tim,ans,tl;
10 int hc[N],hd[N],dfn[N],low[N],cir[N],cw[N],w[N],sta[N],f[N],du[N];
11 bool vis[N],in[N];
12 char bu[100011],*cr,*cl;
13 int read()
14 {
15     int x=0;char ch=gc;
16     while( gs) ch=gc;
17     while(!gs) x=x*10+ch-48,ch=gc;
18     return x;
19 }
20 struct edge{
21     int n,v;
22 }e[M];
23 void add(int u,int v)
24 {
25     e[++tot]=(edge){hd[u],v};
26     hd[u]=tot;
27 }
28 struct Edge{
29     int n,v;
30 }E[M]; 
31 void addcir(int u,int v)
32 {
33     du[v]++;
34     E[++tot]=(Edge){hc[u],v};
35     hc[u]=tot;
36 }
37 void dfs(int po)
38 {
39     if(!dfn[po]) dfn[po]=low[po]=++tim;
40     sta[++tl]=po,in[po]=1;
41     vis[po]=1;
42     for(int i=hd[po];i;i=e[i].n)
43     {
44         int v=e[i].v;
45         if(vis[v]&&in[v]) low[po]=min(low[po],dfn[v]);
46         else if(!vis[v]) 
47         {
48             dfs(v);
49             low[po]=min(low[po],low[v]);
50         }
51      } 
52     if(dfn[po]==low[po])
53     {
54         bool bb=0;
55         cnt++;
56         while(!bb){
57             if(sta[tl]==po) bb=1;
58             cir[sta[tl]]=cnt;
59             cw[cnt]+=w[sta[tl]];
60             in[sta[tl]]=0;
61             sta[tl--]=0;
62         }
63     }
64 }
65 void dfs1(int po,int sum)
66 {
67     if(sum<=f[po]) return ;
68     f[po]=sum;
69     vis[po]=1;
70     ans=max(ans,sum);
71     for(int i=hc[po];i;i=E[i].n)
72     {
73         int v=E[i].v;
74         dfs1(v,sum+cw[v]);
75      } 
76 }
77 int main()
78 {
79      r(n),r(m);
80      for(int i=1;i<=n;i++) r(w[i]);
81      for(int i=1;i<=m;i++)
82      {
83          int u,v;
84          r(u),r(v);
85          add(u,v);
86      }
87      for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
88      tot=0;
89      for(int i=1;i<=n;i++) 
90          for(int j=hd[i];j;j=e[j].n) 
91              if(cir[i]!=cir[e[j].v]) 
92                  addcir(cir[i],cir[e[j].v]);
93      memset(vis,0,sizeof(vis));memset(f,-1,sizeof(f));
94      for(int i=1;i<=cnt;i++) if(du[i]==0&&vis[i]==0) dfs1(i,cw[i]);
95      printf("%d",ans); 
96      return 0;
97  } 
View Code

缩点了以后整个图就是一个DAG(有向无环图)

这道题主要是缩点然后dfs一遍就可以了,也可以用DP做(不过我没写DP)。

这道题真的和今天T3基本一样!改改细节就可以了!QAQ!

2.当然是今天T3

大部分和上面相同 但要是dfs的话会T掉一个点

于是乎 借鉴题解(考虑到固定1个点出发) 写了spfa(呜呜呜spfa写错了一个地方调了半个小时)

参考代码如下:

  1 #include 
  2 #include  
  3 #include 
  4 #define gc cr==cl&&(cr=(cl=bu)+fread(bu,1,100000,stdin),cl==cr)?EOF:*cl++
  5 #define gs (ch<'0'||ch>'9')
  6 #define r(x) x=read()
  7 using namespace std;
  8 const int N=5e5+111,M=5e5+111;
  9 int n,m,tot,cnt,tim,ans,tl,p,S;
 10 int que[N],hc[N],hd[N],dfn[N],low[N],cir[N],cw[N],w[N],sta[N],dis[N];
 11 bool in[N],book[N],book1[N];
 12 char bu[100011],*cr,*cl;
 13 int read()
 14 {
 15     int x=0;char ch=gc;
 16     while( gs) ch=gc;
 17     while(!gs) x=x*10+ch-48,ch=gc;
 18     return x;
 19 }
 20 struct edge{
 21     int n,v;
 22 }e[M];
 23 void add(int u,int v)
 24 {
 25     e[++tot]=(edge){hd[u],v};
 26     hd[u]=tot;
 27 }
 28 struct Edge{
 29     int n,v,w;
 30 }E[M]; 
 31 void addcir(int u,int v,int w)
 32 {
 33     E[++tot]=(Edge){hc[u],v,w};
 34     hc[u]=tot;
 35 }
 36 void dfs(int po)
 37 {
 38     dfn[po]=low[po]=++tim;
 39     sta[++tl]=po,in[po]=1;
 40     for(int i=hd[po];i;i=e[i].n)
 41     {
 42         int v=e[i].v;
 43         if(dfn[v]&&in[v]) low[po]=min(low[po],dfn[v]);
 44         else if(!dfn[v]) 
 45         {
 46             dfs(v);
 47             low[po]=min(low[po],low[v]);
 48         }
 49      } 
 50     if(dfn[po]==low[po])
 51     {
 52         bool bb=0;
 53         cnt++;
 54         while(!bb){
 55             if(sta[tl]==po) bb=1;
 56             if(book[sta[tl]]) book1[cnt]=1;
 57             cir[sta[tl]]=cnt;
 58             cw[cnt]-=w[sta[tl]];
 59             in[sta[tl]]=0;
 60             sta[tl--]=0;
 61         }
 62     }
 63 }
 64 void spfa()
 65 {
 66     S=cir[S];
 67     memset(book,0,sizeof(book));
 68     int he=1,ta=2;
 69     que[he]=S; 
 70     while(he<ta) 
 71     {
 72         int tt=que[he];
 73         for(int i=hc[tt];i;i=E[i].n)
 74         {
 75             int v=E[i].v;
 76             if(dis[tt]+E[i].w<dis[v]) 
 77             {
 78                 dis[v]=dis[tt]+E[i].w;
 79                 if(!book[v]) 
 80                 {
 81                     que[ta++]=v;
 82                     book[v]=1;
 83                 }
 84             }
 85             }    
 86         book[tt]=0;
 87         he++;
 88     }
 89     for(int i=1;i<=cnt;i++) if(book1[i])ans=min(ans,dis[i]);
 90     ans+=cw[S];
 91     ans*=-1;
 92 }
 93 int main()
 94 {
 95      freopen("atm.in","r",stdin);
 96      freopen("atm.out","w",stdout); 
 97      r(n),r(m);     
 98      for(int i=1;i<=m;i++)
 99      {
100          int u,v;
101          r(u),r(v);
102          add(u,v);
103      }
104      for(int i=1;i<=n;i++) r(w[i]);
105      r(S),r(p);
106      for(int i=1;i<=p;i++){int x;r(x);book[x]=1;}
107      dfs(S);
108      tot=0;
109      for(int i=1;i<=n;i++) 
110          if(dfn[i]) for(int j=hd[i];j;j=e[j].n) 
111              if(cir[i]!=cir[e[j].v]) 
112                  addcir(cir[i],cir[e[j].v],cw[cir[e[j].v]]);
113      spfa();
114      printf("%d",ans); 
115      return 0;
116  } 
View Code

那么,就先结束啦~

感谢阅读~

 

你可能感兴趣的:(Tarjan缩点)