图论-教授Szu(BZOJ1512)
这题很有意思,这题数据很强,会卡掉很多没考虑特殊情况的代码。
先缩点,然后根据拓扑序,依次更新每个点的路径数。f[i] 表示 i 到 N+1 号点的路径数量,则 f[x] = Σf[y] ,满足条件:有一条边从 x 到 y 。f[N+1] = 1. 可以存个反图,然后在拓扑序上从前往后讨论,更新 f 值。
1 #include <stdio.h> 2 #include <algorithm> 3 #include <queue> 4 #include <stack> 5 #include <vector> 6 7 using namespace std; 8 9 const int _N = 110000; 10 const int P = 36500; 11 12 int N, M, TimeStamp, V_cnt, ans_mx, ans_cnt; 13 int low[_N], dfn[_N], Bel[_N], Ind[_N], f[_N]; 14 bool mk[_N], flag[_N]; 15 vector<int> G[_N], TG[_N]; 16 queue<int> Q; 17 stack<int> S; 18 19 void Ins(int t1, int t2) { G[t1].push_back(t2); return; } 20 21 void Tarjan(int node) 22 { 23 low[node] = dfn[node] = ++TimeStamp; 24 S.push(node), mk[node] = true; 25 for (int i = G[node].size()-1; i >= 0; --i) { 26 int v = G[node][i]; 27 if (!dfn[v]) { 28 Tarjan(v); 29 low[node] = min(low[node], low[v]); 30 } else if (mk[v]) { 31 low[node] = min(low[node], dfn[v]); 32 } 33 } 34 if (dfn[node] == low[node]) { 35 int tmp; 36 ++V_cnt; 37 do mk[tmp = S.top()] = false, Bel[tmp] = V_cnt, S.pop(); 38 while (tmp != node); 39 } 40 return; 41 } 42 43 int main() 44 { 45 int i, j, t1, t2; 46 scanf("%d%d", &N, &M), ++N; 47 for (i = 1; i <= M; ++i) 48 scanf("%d%d", &t1, &t2), Ins(t2, t1); 49 for (i = 1; i <= N; ++i) 50 if (!dfn[i]) Tarjan(i); 51 for (i = 1; i <= N; ++i) { 52 for (j = G[i].size()-1; j >= 0; --j) { 53 int v = G[i][j]; 54 if (Bel[v] == Bel[i]) flag[Bel[v]] = true; 55 else TG[Bel[i]].push_back(Bel[v]), ++Ind[Bel[v]]; 56 } 57 } 58 f[Bel[N]] = flag[Bel[N]] ? P+1 : 1; 59 ans_mx = max(ans_mx, f[Bel[N]]); 60 for (i = 1; i <= V_cnt; ++i) 61 if (!Ind[i]) Q.push(i); 62 while (!Q.empty()) { 63 int p = Q.front(); Q.pop(); 64 for (j = TG[p].size()-1; j >= 0; --j) { 65 int v = TG[p][j]; 66 if (f[v] != P+1) { 67 if (flag[v]) { 68 if (f[p] > 0) f[v] = P+1; 69 } else { 70 if ((f[v] += f[p]) > P) f[v] = P+1; 71 } 72 } 73 ans_mx = max(ans_mx, f[v]); 74 if (!--Ind[v]) Q.push(v); 75 } 76 } 77 if (ans_mx == P+1) printf("zawsze\n"); 78 else printf("%d\n", ans_mx); 79 ans_cnt = 0; 80 for (i = 1; i < N; ++i) 81 if (f[Bel[i]] == ans_mx) ++ans_cnt; 82 printf("%d\n", ans_cnt); 83 for (i = 1; i < N; ++i) 84 if (f[Bel[i]] == ans_mx) printf("%d ", i); 85 return 0; 86 }
题目
教授Szu | ||
|
问题描述
Byteotian 大学由一幢主建筑和n个小别墅组成. 它们之间许多单向的道路连接,任意两个建筑之间可能有多条单向路,也有可能一条路从自己出发并回到自己.任意两个建筑之间都是连通的(即要么可以从A走到B,要么可以从B走到A).
现在Byteotian大学想聘请著名的Szu教授. 作为一名出众的教授,他的行为非常的奇特:他希望每天都能走一条不同的路径去大学主建筑,其中一条道路可以走多次,一个建筑也可以经过多次,两条道路只要经过的任意一条道路不同即不同(注意,两条不同的道路连接着两个同样的建筑也是不同的).
在知道了大学中所有道路的分布以后可以帮助我们知道从哪些地方出发可以有最多不同的道路去主建筑,因为知道了这些地方可以使得Szu教授在大学中工作的尽量久.如果有多个这样的地方,把他们都找出来. 如果从某个地方出发有超过36500 条不同的路径通向主建筑,那么我们认为Szu教授可以在这里永远待下去.
输入格式
第一行两个整数 n 和 m ( 1<= n, m<= 100000) 表示大学里别墅的个数和道路条数(别墅编号从1到n,大学主建筑的编号为n + 1).
接下来m行每行两个整数 ai, bi ( 1 <=ai, bi<= n + 1 for 1 i m) 表示一条单向路.
注意:
1:所有方案数超过36500的点都是等价的
2:本题可能有自环
输出格式
第一行输出路径最多条数,如果超过了36500,那么打印''zawsze'' .
第二行一个整数表示一共有多少个别墅可以满足第一行的条件,
第三行顺序给出这些别墅的编号.
样例输入 1
3 5
1 2
1 3
2 3
3 4
3 4
样例输出 1
4
1
1
样例输入 2
4 7
1 2
2 2
3 2
2 3
3 4
4 5
3 4
样例输出 2
zawsze
3
1 2 3