SDUT 2170 The Largest SCC bfs+tarjan
题意:
给你一个n个点,m条有向边的图,然后给你k个操作,每次把第i个边改变成无向边。然后求该图的强连通块里面点数最多的值
思路:
首先bfs求出每个点可达的边,然后tarjan求出强连通块。每次改变边时,如果这条边的两个端点在同一连通块(u,v),直接输出最多。如果不在同一连通块,首先加上这两个连通块的个数组成新的连通块,然后枚举i u->i ,i>v满足,然后i不属于u或者v的连通块,然后加上该连通块数量即可。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll __int64 #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 20010 #define N 1010 using namespace std; const int mod = 1000000007; bool isok[N][N]; struct node { int u,v; }nd[M]; struct side { int v; int next; }g[M]; int dfn[N],low[N]; int belong[N],stk[N]; bool ins[N]; int cnt,top,idx; int head[N],ct; bool vt[N]; int num[N]; int n,m,k; int ans; void init() { for (int i = 0; i <= n; ++i) { dfn[i] = low[i] = belong[i] = -1; ins[i] = false; head[i] = -1; num[i] = 0; } cnt = idx = ct = top = 0; } void add(int u,int v) { g[ct].v = v; g[ct].next = head[u]; head[u] = ct++; } void bfs(int s) { queue<int> Q; vt[s] = true; Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; if (!vt[v]) { vt[v] = true; isok[s][v] = true; Q.push(v); } } } } void tarjan(int u) { int i,v; low[u] = dfn[u] = ++idx; stk[++top] = u; ins[u] = true; for (i = head[u]; i != -1; i = g[i].next) { v = g[i].v; if (dfn[v] == -1) { tarjan(v); low[u] = min(low[u],low[v]); } else if (ins[v]) { low[u] = min(low[u],dfn[v]); } } if (dfn[u] == low[u]) { cnt++; do{ v = stk[top--]; ins[v] = false; belong[v] = cnt; num[cnt]++; }while (v != u); ans = max(ans,num[cnt]); } } int main() { // Read(); int T,i,j; scanf("%d",&T); while (T--) { scanf("%d%d%d",&n,&m,&k); init(); for (i = 1; i <= m; ++i) { scanf("%d%d",&nd[i].u,&nd[i].v); add(nd[i].u,nd[i].v); } CL(isok,false);//标记两点是否可达 //找出每个每个点可达的点 for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) vt[j] = false; bfs(i); } ans = 0; for (i = 1; i <= n; ++i) { if (dfn[i] == -1) { tarjan(i); } } int x; while (k--) { scanf("%d",&x); int u = nd[x].u; int v = nd[x].v; int sum = ans; if (belong[u] == belong[v]) { printf("%d\n",sum); } else { int tmp = num[belong[u]] + num[belong[v]]; for (j = 1; j <= n; ++j) vt[j] = false;//这里表示该连通块是否已经加入 for (i = 1; i <= n; ++i) { if (belong[i] == belong[u] || belong[i] == belong[v]) continue; if (isok[u][i] && isok[i][v] && !vt[belong[i]]) { vt[belong[i]] = true; tmp += num[belong[i]]; } } sum = max(sum,tmp); printf("%d\n",sum); } } } return 0; }