Codeforces Gym101246G:Revolutionary Roads(DFS+思维)
http://codeforces.com/gym/101246/problem/G
题意:有一个n个点m条边的有向图,现在可以修改某一条有向边使得其为无向边,问修改哪些边可以使得修改后的强连通分量的点数最多,输出。
思路:
要使得修改边后的强连通分量的点数最多,假设当前修改的边的入点为u,出点为v,那么能在修改当前的边之后在强连通分量里面的点i,当且仅当修改边之前u能到达i并且i能到达v,然后修改之后,i就能通过v回到u,这样就是强连通的了。比如上面这个样例的1->5这条边,1(u)能到达1、2、3、4、6、5并且1、2、3、4、6、5能到达5(v),因此修改1->5这条边之后,整个图都是强连通的了。
判断点与点之间是否可达,就可以对每一个点都进行一下DFS,DFS中遍历到的点都是可达的。
处理出关系之后,就可以枚举边,判断对于当前的边,有哪些点可以在修改后的强连通分量里面。
时间复杂度为O(mn)。
注意:m可以为0!!!没有边的情况下,输出的点数应该是1而不是0!
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 #define M 20010 5 #define N 1010 6 struct Edge { 7 int v, nxt; 8 } edge[M]; 9 int vis[N], head[N], tot, mp[N][N], ans[M], u[M], v[M]; 10 11 void Add(int u, int v) { edge[tot] = (Edge) {v, head[u]}; head[u] = tot++; } 12 13 void dfs(int u, int st) { 14 for(int i = head[u]; ~i; i = edge[i].nxt) { 15 int v = edge[i].v; 16 if(vis[v]) continue; 17 mp[st][v] = 1; 18 vis[v] = 1; dfs(v, st); 19 } 20 } 21 22 int main() { 23 freopen("input.txt", "r", stdin); 24 freopen("output.txt", "w", stdout); 25 int n, m; 26 scanf("%d%d", &n, &m); 27 if(!m) { puts("1\n0"); return 0; } 28 memset(head, -1, sizeof(head)); 29 for(int i = 1; i <= m; i++) { 30 scanf("%d%d", &u[i], &v[i]); 31 Add(u[i], v[i]); 32 } 33 for(int i = 1; i <= n; i++) { 34 mp[i][i] = 1; // 判断是否可达 35 memset(vis, 0, sizeof(vis)); 36 vis[i] = 1; dfs(i, i); 37 } 38 int res = 0, cnt = 0; 39 for(int i = 1; i <= m; i++) { 40 int now = 0; 41 for(int j = 1; j <= n; j++) if(mp[u[i]][j] && mp[j][v[i]]) now++; 42 if(now > res) { res = now; cnt = 0; ans[++cnt] = i; } 43 else if(now == res) ans[++cnt] = i; 44 } 45 printf("%d\n%d\n", res, cnt); 46 for(int i = 1; i <= cnt; i++) printf("%d ", ans[i]); 47 return 0; 48 }