zoukankan      html  css  js  c++  java
  • 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
    0"); 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
    %d
    ", res, cnt);
    46     for(int i = 1; i <= cnt; i++) printf("%d ", ans[i]);
    47     return 0;
    48 }
  • 相关阅读:
    【并发编程】多线程并发最佳实践
    【并发编程】死锁
    【并发编程】【JDK源码】J.U.C--线程池
    【并发编程】【JDK源码】J.U.C--组件FutureTask、ForkJoin、BlockingQueue
    【JVM】关于类加载器准备阶段的一道面试题目
    【并发编程】【JDK源码】J.U.C--AQS 及其同步组件(2/2)
    【并发编程】线程安全策略
    JSP 9大内置对象详解
    Jquery中的bind(),live(),delegate(),on()绑定事件方式
    阻止事件冒泡
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6548025.html
Copyright © 2011-2022 走看看