ZOJ 3620 Information(强联通分量)

本文探讨了在有向图中删除一个节点后,使得剩余图中最大强连通分量最小化的策略。通过Kosaraju或Tarjan算法实现强连通分量的查找,并对每种情况下的分量大小进行比较,最终确定最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Information

Time Limit: 2 Seconds      Memory Limit: 32768 KB

It is a war between Country Alpha and Country Beta. Country Alpha gets following information about Country Beta:

Country Beta has n (2 <= n <= 100) cities numbered from 0 to n-1. Each city has a transmitter and a receiver. One city is able to transmit important information by its transmitter to another city. Meanwhile, if there's information transmitted to one city, it is able to receive the information by its receiver. Of course, it is OK that one city doesn't transmit any information to another city and that if no information transmitted to one city, the city receives no information. Thus, a quantity of cities are able to constitute a group. In a group, any city is able to transmit the information to any city in the group directly or indirectly. Of course, one city belongs to only one group.

Now, Country Alpha wants to demolish one city of Country Beta. Thus, Alpha will make the number of cities in the largest group as small as possible.

Input

Ther are multiple test cases (about 200 cases). There is a blank line between each case.

The first line of each case contains two positive integers, n and m (0 <= m <= 9900), in which m indicates the number of the path(es) of the information from one city to another. In each line of following m line(s), there are two positive integers, s, t, indicating that some information is from City s to City t. No same pair of (s,t).

Output

Output the least number of cities in a group, which is the largest group after Country Alpha's attack. By the way, a group must consist of at least two cities, that is, one city is not able to be considered as a group. If there is no group, output 0.

Sample Input
2 2
0 1
1 0
Sample Output
0

题意:求任意去掉有向图中的一个点使其最大强连通分量最小。

思路:第一次做强联通题目,每删一个点就跑一次scc并求最大强连通分量,然后取出最小一个。强连通有两种算法:KosarajuTarjan,后者更高效。

Kosaraju算法

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <vector>
using namespace std;

vector<int> g[109];
vector<int> rg[109];
vector<int> vs;
int cmp[109];
bool used[109];
bool d[109][109];
int n, m;

void add_edge(int from, int to)
{
    g[from].push_back(to);
    rg[to].push_back(from);
}

void dfs(int v)
{
    used[v]=true;
    for(int i=0; i<g[v].size(); i++)
    {
        if(!used[g[v][i]]) dfs(g[v][i]);
    }
    vs.push_back(v);
}

void rdfs(int v, int k)
{
    used[v]=true;
    cmp[k]++;
    for(int i=0; i<rg[v].size(); i++)
    {   if(!used[rg[v][i]]) rdfs(rg[v][i], k);
}
}
int scc()
{
    memset(cmp, 0, sizeof(cmp));
    memset(used, 0, sizeof(used));
    vs.clear();
    for(int i=0; i<n; i++)
    {
        if(!used[i]) dfs(i);
    }
    memset(used, 0, sizeof(used));
    int k=0;
    for(int i=vs.size()-1; i>=0; i--)
    {
        if(!used[vs[i]]) rdfs(vs[i], k++);
    }
    sort(cmp, cmp+k);
    if(cmp[k-1]<2)
        return 0;
    else
        return cmp[k-1];
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        int M=109;
        memset(d, 0, sizeof(d));
        for(int i=0; i<m; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            d[a][b]=true;
        }
        for(int v=0; v<n; v++)
        {
            for(int i=0; i<109; i++)
            {
                for(int j=0; j<109; j++)
                {
                    g[i].clear();
                    rg[i].clear();
                }
            }
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<n; j++)
                {
                    if(i!=v && j!=v && d[i][j])
                    {
                        add_edge(i, j);
                    }
                }
            }
            int s=scc();
            if(s<M)
                M=s;
        }
        printf("%d\n", M);
    }
    return 0;
}

Tarjan算法
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
using namespace std;

int dfn[109], low[109], belong[109], stap[109];
bool instakc[109];
vector<int> edge[109];
int stop, k, ind;
void tarjan(int i, int flag)
{
    dfn[i]=++ind;
    low[i]=ind;
    instakc[i]=true;
    stap[++stop]=i;
    for(int j=0; j<edge[i].size(); j++)
    {
        int e=edge[i][j];
        if(e==flag) continue;
        if(!dfn[e])
        {
            tarjan(e, flag);
            if(low[i] > low[e])
                low[i]=low[e];
        }
        else if(instakc[e] && dfn[e] < low[i])
        {
                low[i]=dfn[e];
        }
    }
    if(low[i]==dfn[i])
    {
        k++;
        int j;
        do
        {
            j=stap[stop--];
            instakc[j]=false;
            belong[k]++;
        }
        while(i!=j);
    }
}
int solve(int n, int flag)
{
    memset(dfn, 0, sizeof(dfn));
    memset(belong, 0, sizeof(belong));
    memset(stap, 0, sizeof(stap));
    memset(instakc, 0, sizeof(instakc));
    stop=0, k=0, ind=0;
    for(int i=0; i<n; i++)
    {
        if(!dfn[i] && i!=flag)
        {
            tarjan(i, flag);
        }
    }
    sort(belong, belong+k+1);
    if(belong[k]<2) return 0;
    else return belong[k];
}
int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        for(int i=0; i<109; i++)
            edge[i].clear();
        for(int i=0; i<m; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            edge[a].push_back(b);
        }
        int M=109;
        for(int i=0; i<n; i++)
        {
            int c=solve(n, i);
            if(M>c)
            {
                M=c;
            }
        }
        printf("%d\n", M);
    }
    return 0;
}




 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值