P1726 上白泽慧音

题目链接:P1726

 

题目大意:

给一个有向图,找出最大的强连通分量,如果有多个最大的强连通分量,输出序号字典序最小的。

 

解题思路:

tarjan模板题,洛谷给成蓝题感觉难度给高了。找字典序最小的时候,如果有两个强连通分量大小相同,则输出代表元序号最小的那一个scc,因为不可能有两个强连通分量的代表元相同,假如有的话,那这两个强连通分量可以合并构成一个更大的scc。

 

参考代码:

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <vector>
  7 #define N 50010
  8 using namespace std;
  9 /*
 10     head,nxt,to 链式前向星存图
 11     belong 强连通分量代表元
 12     col 每个强连通分量的大小
 13     dfn,low: tarjan算法所用数组
 14     s:tarjan算法手写栈
 15     vis:tarjan时标记是否访问过
 16 */
 17 int cnt,id,tot; // cnt为链星的标号,id为dfn,low的标号,tot为栈s的标号
 18 int head[N],nxt[N],to[N],belong[N],dfn[N],low[N],s[N],col[N];
 19 bool vis[N];
 20 
 21 inline int read()
 22 {
 23     int x = 0, y = 1; char c = getchar();
 24     while(c < '0' || c > '9') {if(c == '-') y = -1; c = getchar();}
 25     while(c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
 26     return x*y;
 27 }
 28 // 链星加边
 29 void add(int u, int v)
 30 {
 31     nxt[++cnt] = head[u];
 32     head[u] = cnt;
 33     to[cnt] = v;
 34 }
 35 // tarjan
 36 void tarjan(int u)
 37 {
 38     vis[u] = true;
 39     dfn[u] = low[u] = ++id;
 40     s[++tot] = u;
 41     for(int i = head[u]; ~i; i = nxt[i])
 42     {
 43         int v = to[i];
 44         if(!dfn[v])
 45         {
 46             tarjan(v);
 47             low[u] = min(low[u],low[v]);
 48         } else if(vis[v]) low[u] = min(low[u],low[v]);
 49     }
 50     if(dfn[u] == low[u])
 51     {
 52         vis[u] = false;
 53         belong[u] = u;
 54         col[u]++;
 55         while(s[tot] != u)
 56         {
 57             vis[s[tot]] = false;
 58             belong[s[tot]] = u;
 59             col[u]++;
 60             tot--;
 61         }
 62         tot--;
 63     }
 64 }
 65 // 初始化
 66 void init()
 67 {
 68     cnt = -1;
 69     tot = id = 0;
 70     memset(vis,false,sizeof(vis));
 71     memset(head,-1,sizeof(head));
 72 }
 73 int main()
 74 {
 75     init();
 76     // maxx,maxn分别用来存最大的scc的大小以及最大的scc的代表元
 77     int maxx = -1;
 78     int maxn;
 79     int n,m;
 80     int u,v,t;
 81     n = read();
 82     m = read();
 83     for(int i = 0; i < m; i++)
 84     {
 85         u = read();
 86         v = read();
 87         t = read();
 88         if(t == 1)
 89         {
 90             add(u,v);
 91         } else if(t == 2) { // 双向边,加两次
 92             add(u,v);
 93             add(v,u);
 94         }
 95     }
 96     // 保证图不连通时,每个点都tarjan到了
 97     for(int i = 1; i <= n; i++)
 98     {
 99         if(!dfn[i])
100             tarjan(i);
101     }
102     // 找最大的scc同时找字典序最小的
103     for(int i = 1; i <= n; i++)
104     {
105         if(col[belong[i]] > maxx)
106         {
107             maxx = col[belong[i]];
108             maxn = belong[i];
109         } else if(col[belong[i]] == maxx && maxn > belong[i]) {
110             maxn = belong[i];
111         }
112     }
113     // 输出
114     printf("%d\n",maxx);
115     for(int i = 1; i <= n; i++)
116     {
117         if(belong[i] == maxn)
118             printf("%d ",i);
119     }
120     return 0;
121 }

 

posted @ 2020-11-16 10:38  不敢说的梦  阅读(165)  评论(0)    收藏  举报