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;
}
View Code

 

 

posted @ 2013-06-01 23:47  E_star  阅读(376)  评论(0编辑  收藏  举报