tarjan
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 struct node 20 { 21 int d; 22 node *to; 23 }*e[maxn]; 24 25 int id,dfn[maxn],low[maxn],tot_st,st[maxn],m,group[maxn]; 26 bool vis[maxn],vis_st[maxn]; 27 28 /** 29 id:编号 每增加一个点,++id 30 每增加一个点,加入栈中 31 low:点的编号 32 dfn:点以及后续点通过一条边能到的最小编号点的编号 33 34 同一个类 dfn[d]=low[d] 栈中,第x个数d到栈顶 任意点的low值为dfn[d] 35 st:栈 若点变为在一个类中时,从栈中弹出 36 vis_st : 当点还未标记到类中时,可以使用 37 38 m:类的个数 39 group:每个点所在的类 40 **/ 41 42 void tarjan(int d) 43 { 44 int dd; 45 vis[d]=1; 46 dfn[d]=low[d]=++id; 47 st[++tot_st]=d; 48 node *p=e[d]; 49 while (p) 50 { 51 dd=p->d; 52 if (!vis[dd]) 53 { 54 tarjan(dd); 55 low[d]=min(low[d],low[dd]); 56 } 57 else if (!vis_st[dd]) 58 low[d]=min(low[d],dfn[dd]); 59 p=p->to; 60 } 61 if (dfn[d]==low[d]) 62 { 63 m++; 64 int g=tot_st; 65 while (st[tot_st]!=d) 66 { 67 group[st[tot_st]]=m; 68 vis_st[st[tot_st]]=1; 69 tot_st--; 70 } 71 group[st[tot_st]]=m; 72 vis_st[st[tot_st]]=1; 73 tot_st--; 74 g-=tot_st; ///类的大小 75 } 76 } 77 78 int main() 79 { 80 node *p; 81 int n,q,x,y,i; 82 scanf("%d%d",&n,&q); 83 while (q--) 84 { 85 scanf("%d%d",&x,&y); 86 ///注意单边还是双边 87 p=new node(); 88 p->d=y; 89 p->to=e[x]; 90 e[x]=p; 91 } 92 for (i=1;i<=n;i++) 93 if (!vis[i]) 94 tarjan(i); 95 return 0; 96 } 97 /* 98 99 */
luogu P1726 上白泽慧音
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 struct node 20 { 21 int d; 22 node *to; 23 }*e[maxn]; 24 25 int id,dfn[maxn],low[maxn],tot_st,st[maxn],m,group[maxn]; ///m:类的个数 26 bool vis[maxn],vis_st[maxn]; ///st:栈,存储未被'类‘标签的点 27 28 int ind,maxg=0,md; 29 30 void tarjan(int d) 31 { 32 int dd; 33 vis[d]=1; 34 dfn[d]=low[d]=++id; 35 st[++tot_st]=d; 36 node *p=e[d]; 37 while (p) 38 { 39 dd=p->d; 40 if (!vis[dd]) 41 { 42 tarjan(dd); 43 low[d]=min(low[d],low[dd]); 44 } 45 else if (!vis_st[dd]) 46 low[d]=min(low[d],dfn[dd]); 47 p=p->to; 48 } 49 if (dfn[d]==low[d]) 50 { 51 m++; 52 int g=tot_st,mind=inf; 53 while (st[tot_st]!=d) 54 { 55 group[st[tot_st]]=m; 56 mind=min(mind,st[tot_st]); 57 vis_st[st[tot_st]]=1; 58 tot_st--; 59 } 60 group[st[tot_st]]=m; 61 mind=min(mind,st[tot_st]); 62 vis_st[st[tot_st]]=1; 63 tot_st--; 64 g-=tot_st; 65 if (maxg<g || (maxg==g && mind<md)) 66 ind=m,maxg=g,md=mind; 67 } 68 } 69 70 int main() 71 { 72 node *p; 73 int n,q,x,y,z,i; 74 scanf("%d%d",&n,&q); 75 while (q--) 76 { 77 scanf("%d%d%d",&x,&y,&z); 78 p=new node(); 79 p->d=y; 80 p->to=e[x]; 81 e[x]=p; 82 if (z==2) 83 { 84 p=new node(); 85 p->d=x; 86 p->to=e[y]; 87 e[y]=p; 88 } 89 } 90 for (i=1;i<=n;i++) 91 if (!vis[i]) 92 tarjan(i); 93 printf("%d",maxg); 94 bool v=0; 95 for (i=1;i<=n;i++) 96 if (group[i]==ind) 97 { 98 if (!v) 99 printf(" "),v=1; 100 else 101 printf(" "); 102 printf("%d",i); 103 } 104 return 0; 105 } 106 /* 107 108 */
luogu P3387 【模板】缩点
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 /* 20 题目描述 21 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。 22 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。 23 24 第一行,n,m 25 第二行,n个整数,依次代表点权 26 第三至m+2行,每行两个整数u,v,表示u->v有一条有向边 27 28 共一行,最大的点权之和。 29 30 2 2 31 1 1 32 1 2 33 2 1 34 35 2 36 */ 37 38 struct node 39 { 40 int d; 41 node *to; 42 }*e[maxn],*gr[maxn]; 43 44 int id,dfn[maxn],low[maxn],tot_st,st[maxn],m,group[maxn]; 45 bool vis[maxn],vis_st[maxn]; 46 int v[maxn],ans[maxn];/// 47 48 /** 49 id:编号 每增加一个点,++id 50 每增加一个点,加入栈中 51 low:点的编号 52 dfn:点以及后续点通过一条边能到的最小编号点的编号 53 54 同一个类 dfn[d]=low[d] 栈中,第x个数d到栈顶 任意点的low值为dfn[d] 55 st:栈 若点变为在一个类中时,从栈中弹出 56 vis_st : 当点还未标记到类中时,可以使用 57 58 m:类的个数 59 group:每个点所在的类 60 **/ 61 62 void tarjan(int d) 63 { 64 int dd; 65 vis[d]=1; 66 dfn[d]=low[d]=++id; 67 st[++tot_st]=d; 68 node *p=e[d]; 69 while (p) 70 { 71 dd=p->d; 72 if (!vis[dd]) 73 { 74 tarjan(dd); 75 low[d]=min(low[d],low[dd]); 76 } 77 else if (!vis_st[dd]) 78 low[d]=min(low[d],dfn[dd]); 79 p=p->to; 80 } 81 if (dfn[d]==low[d]) 82 { 83 m++; 84 while (st[tot_st]!=d) 85 { 86 group[st[tot_st]]=m; /// 87 vis_st[st[tot_st]]=1; 88 tot_st--; 89 } 90 group[st[tot_st]]=m; /// 91 vis_st[st[tot_st]]=1; 92 tot_st--; 93 } 94 } 95 96 void dfs(int d) 97 { 98 node *p=gr[d]; 99 int dd,add=0; 100 vis[d]=1; 101 while (p) 102 { 103 dd=p->d; 104 if (!vis[dd]) 105 dfs(dd); 106 add=max(add,ans[dd]); ///点d到达下一个点,最大的值 千万注意这个是放在外面的 107 p=p->to; 108 } 109 ans[d]+=add; 110 } 111 112 int main() 113 { 114 node *p,*r; 115 int n,q,x,y,i,d; 116 scanf("%d%d",&n,&q); 117 118 for (i=1;i<=n;i++) ///点权 119 scanf("%d",&v[i]); 120 121 while (q--) 122 { 123 scanf("%d%d",&x,&y); 124 ///注意单边还是双边 125 p=new node(); 126 p->d=y; 127 p->to=e[x]; 128 e[x]=p; 129 } 130 for (i=1;i<=n;i++) 131 if (!vis[i]) 132 tarjan(i); 133 134 for (i=1;i<=n;i++) 135 { 136 ans[group[i]]+=v[i]; ///同一类,能互相访问所有的点 137 p=e[i]; 138 while (p) 139 { 140 d=p->d; 141 if (group[i]!=group[d]) 142 { 143 r=new node(); ///变量名要有区分 144 r->d=group[d]; 145 r->to=gr[group[i]]; 146 gr[group[i]]=r; 147 148 // printf("%d %d ",group[i],group[d]); 149 } 150 p=p->to; 151 } 152 } 153 154 ///tarjan+缩点后无环 155 memset(vis,0,sizeof(vis)); 156 for (i=1;i<=n;i++) 157 if (!vis[i]) 158 dfs(i); 159 int maxa=0; 160 for (i=1;i<=n;i++) 161 maxa=max(maxa,ans[i]); 162 printf("%d",maxa); 163 return 0; 164 } 165 /* 166 3 2 167 1 2 3 168 1 2 169 1 3 170 */
luogu P3388 【模板】割点(割顶)