您的位置:首页 > 其它

ZOJ 3620 Information(强联通分量)

2015-07-20 16:04 393 查看
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 mul
4000
tiple 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并求最大强连通分量,然后取出最小一个。强连通有两种算法:Kosaraju和Tarjan,后者更高效。
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;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  联通 zoj