upc组队赛14 Communication【并查集+floyd /Tarjan】

Communication

题目描述

The Ministry of Communication has an extremely wonderful message system, designed by the President himself. For maximum efficiency, each office in the Ministry can send a message directly to some, but not necessarily all, other offices. These connections are not always two-way, because sometimes one office should have the power to send a message to another office, but the other office should not have the power to send one back. This may seem unfair, or even illogical, to uneducated people, but this is the will of the President.
There are so many offices now that the situation has become rather confusing, so the President has decided to reorganize the Ministry to be better adapted to the message system.
The President will divide the Ministry into new departments based on two simple principles:

  1. If A and B are in the same department then A can transmit a message to B, and B can transmit a message to A.
  2. If A can transmit a message to B, and B can transmit a message to A, then A and B are in the same department.
    How many departments will the reorganized Ministry have?

输入

Input starts with a line containing a single integer N, with 0 < N ≤ 100. This tells you how many test cases there will be.
Each following pair lines contains a single test case. The first line of each test case contains an integer n, with 1 < n ≤ 200. This is the number of offices the Ministry has. The second line starts with an integer e with 0 < e <n2/4. This tells you how many individual direct (and directed) connections the Ministry has. Following this are e pairs of integers a, b, with 0 ≤a < b ≤ n − 1. These pairs indicate that there is a connection from a to b. There is at most one direct connection going out from one office and into another.

输出

Each line of output is an integer saying how many departments the Ministry corresponding to that test case will have.

样例输入

3
6
2 0 5 5 0
5
7 0 1 0 2 1 0 1 3 2 4 3 1 4 2
3
4 0 1 0 2 1 0 1 2

样例输出

5
2
2

题意

求有几个能够互相联系的部门(即连通块数量)

题解

并查集 ,但是因为有出现环的情况,所以需要用到floyd判环 ,注意floyd内使用min函数会超时
思路参考

先标记那两个点之间有关系 因为想使用并查集 但并查集的边是无方向的 所以必须满足两点之间可以相互通话才使用并查集连接
分两种情况对待1、2的判断条件:
1、如果f[i][j]=1&&f[j][i]=1说明他们符合条件1并且是双向的边 那就可以把它们放进并查集
2、条件是成环 所以用floyd先判断是否成环:如果成环 则dis[i][j]和dis[j][i]一定是小于初始化的值的 也把他们放进并查集
最后跑for 判断有几个点的pre[i]==i 输出个数即可

这题也可以用Tarjan,但是我还不会这个算法- -先挖个坑

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define scac(x) scanf("%c",&x)
#define sca(x) scanf("%d",&x)
#define sca2(x,y) scanf("%d%d",&x,&y)
#define sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define scl(x) scanf("%lld",&x)
#define scl2(x,y) scanf("%lld%lld",&x,&y)
#define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define pri(x) printf("%d
",x)
#define pri2(x,y) printf("%d %d
",x,y)
#define pri3(x,y,z) printf("%d %d %d
",x,y,z)
#define prl(x) printf("%lld
",x)
#define prl2(x,y) printf("%lld %lld
",x,y)
#define prl3(x,y,z) printf("%lld %lld %lld
",x,y,z)
#define ll long long
#define LL long long
#define pb push_back
#define mp make_pair
#define P pair<int,int>
#define PLL pair<ll,ll>
#define PI acos(1.0)
#define eps 1e-6
#define inf 1e17
#define INF 0x3f3f3f3f
#define N 5005
const int maxn = 2000005;
int t,n,m,u,v,ans;
int e[N][N],dis[N][N];
int fa[N];
P a[N];
void init()
{
  rep(i,0,N)
  {
    fa[i] = i;
    rep(j,0,N)
    {
      e[i][j] = 0;
      dis[i][j] = INF;
    }
  }
}
void add(int i,int u,int v)
{
  a[i] = mp(u,v);
  e[u][v] = 1;
  dis[u][v] = 1;
}
void floyd(int n)
{
  rep(k,0,n)  rep(i,0,n)  rep(j,0,n) 
    if(dis[i][j] > dis[i][k] + dis[k][j])
      dis[i][j] = dis[i][k]+dis[k][j] ;
}
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
void join(int x,int y)
{
  if(find(x)!=find(y))
    fa[find(y)] = find(x);
}
int main()
{
  sca(t);
  while(t--)
  {
    init();
    sca2(n,m);
    rep(i,0,m)
    {
      sca2(u,v);
      add(i,u,v);
    }
    floyd(n);
    rep(i,0,m)
    {
      u = a[i].first, v = a[i].second;
    
      if(e[v][u] || (dis[u][v] != INF && dis[v][u] != INF))
        join(u,v);
    }
    ans = 0;
    rep(i,0,n)
    {
      if(fa[i] == i)
        ans++;
    }
    pri(ans);
  }
}

原文地址:https://www.cnblogs.com/llke/p/10806213.html