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 }

 

转载于:https://www.cnblogs.com/fightfordream/p/6548025.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值