UVA - 459 (并查集)

链接:



http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22649

题意就是求有多少联通的块。(一开始自己脑补成双联通 然后死也过不了样例。

这道题目的读入也是挺恶心的。

#pragma comment(linker, "/STACK:10240000,10240000")
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define mod 4294967296
#define MAX 0x3f3f3f3f
#define lson o<<1, l, m
#define rson o<<1|1, m+1, r
#define SZ(x) ((int)ans.size())
#define MAKE make_pair
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define mem(a) memset(a, 0, sizeof(a))
const double pi = acos(-1.0);
const double eps = 1e-9;
const int N = 105;
const int M = 20005;
typedef long long ll;
using namespace std;

int n, m, T;
vector <int> G[N];
int pre[N], iscut[N], bcc[N], dfs_clock, bcc_cnt;

int dfs(int u, int fa) {
    int lowu = pre[u] = ++ dfs_clock;
    int child = 0;
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(!pre[v]) {
            child++;
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv);
            if(lowv >= pre[u]) {
                iscut[u] = 1;
            }
        } else if(pre[v] < pre[u] && v != fa) {
            lowu = min(lowu, pre[v]);
        }
    }
    if(fa < 0 && child == 1) iscut[u] = 0;
    return lowu;
}

void find_scc() {
    mem(pre);
    mem(iscut);
    mem(bcc);
    dfs_clock = bcc_cnt = 0;
    for(int i = 0; i < n; i++) {
        if(pre[i] == 0) dfs(i, -1);
    }
}

int f[N];
int Find(int x) {
    return f[x] == x ? x : f[x] = Find(f[x]);
}

int main()
{
    //freopen("in.txt","r",stdin);
    cin >> T; getchar();getchar();
    int ca = 1;
    while(T--) {
        string s;
        getline(cin, s);

        n = s[0]-'A'+1;
        for(int i = 0; i < n; i++) G[i].clear();

        for(int i = 0; i < n; i++) {
            f[i] = i;
        }
        while(getline(cin, s) && s != "") {
            int x = s[0]-'A';
            int y = s[1]-'A';
            int fa = Find(x);
            int fb = Find(y);
            if(fa != fb) {
                f[fa] = fb;
            }
        }
        int cnt = 0;
        for(int i = 0; i < n; i++) {
            if(f[i] == i) cnt++;
        }
        if(ca > 1) puts(""); ca++;
        cout << cnt << endl;
    }

	return 0;
}
时间: 2024-12-18 10:52:47

UVA - 459 (并查集)的相关文章

UVa 11987 并查集 Almost Union-Find

原文戳这 与以往的并查集不同,这次需要一个删除操作.如果是叶子节点还好,直接修改父亲指针就好. 但是如果要是移动根节点,指向它的所有子节点也会跟着变化. 所以要增加一个永远不会被修改的虚拟根节点,这样就可以把一个点从集合中删除而不影响其它的点了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std

UVa 10129 (并查集 + 欧拉路径) Play on Words

题意: 有n个由小写字母的单词,要求判断是否存在某种排列是的相邻的两个单词,前一个单词末字母与后一个单词首字母相同. 分析: 将单词的两个字母看做节点,则一个单词可以看做一条有向边.那么题中所求的排列就等价于该有向图中是否存在欧拉路径. 在判断之前,首先要确定这个图是连通的,代码中用并查集来实现. 回顾一下存在欧拉路径的条件,全都是偶点或者有且仅有两个奇点.我们用deg来记录每个点的度,出度为1,入度为-1. 程序中判断存在欧拉路径的条件就是:deg全为0 或者 有两个不为0的,其中一个为1一个

UVA 11987 并查集删点

并查集删点就是弄个id记录当前点的id,删除的时候将id设为新的id,忽略原来的id,当然还要注意去改变原来集合需要维护的性质比如元素个数等等. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) m

Graph Connectivity UVA, 459(并查集)

Graph Connectivity UVA, 459 Time Limit: 3000 MS  Graph Connectivity  Consider a graph G formed from a large number of nodes connected by edges. G is said to be connected if a path can be found in 0 or more steps between any pair of nodes in G. For ex

UVA 572 油田连通块-并查集解决

题意:8个方向如果能够连成一块就算是一个连通块,求一共有几个连通块. 分析:网上的题解一般都是dfs,但是今天发现并查集也可以解决,为了方便我自己理解大神的模板,便尝试解这道题目,没想到过了... 1 #include <cstdio> 2 #include <iostream> 3 #include <sstream> 4 #include <cmath> 5 #include <cstring> 6 #include <cstdlib&

UVA - 11987 - Almost Union-Find (又是并查集~)

UVA - 11987 Almost Union-Find Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem A Almost Union-Find I hope you know the beautiful Union-Find structure. In this problem, you're to implement som

UVA - 10596 - Morning Walk (欧拉回路!并查集判断回路)

UVA - 10596 Morning Walk Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu Submit Status Description Problem H Morning Walk Time Limit 3 Seconds Kamal is a Motashota guy. He has got a new job in Chittagong . So, he has moved to Ch

uva 10608 Friends(并查集)

uva 10608 Friends 题目大意:给出两两之间的关系,求出最大的关系网. 解题思路:并查集裸体. #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; const int N = 30005; typedef long long ll; int n, m; in

并查集间单个节点的转移(UVa 11987 Almost Union-Find)

从来没有这么艰难地完成一道算法题过!经过8次失败之后总算提交成功了!所以决定写一篇博文,对并查集的相关内容做一些总结. 普通并查集的操作无非是两种,find_set(x)即找到节点x所在的集合的代表节点,或者是union_set(x,y),即将x和y所在的两个集合合并起来.如下图所示,有左右两个并集 通常,我们会选用并查集中父节点为自己的元素作为这个并查集的代表,例如图中的节点a和节点e.那么,我们如何通过集合中的一个节点找到该节点所在集合的代表节点呢?其实很简单,例如上图中的d节点,它首先通过

uva 1455 - Kingdom(并查集+线段树)

题目链接:uva 1455 - Kingdom 题目大意:平面上又n个城市,初始时城市之间没有任何双向道路相连,要求一次执行指令. road A B :在城市A和城市B之间连接一条双向道路 line C:询问一条y=C的水平线上穿过多少州和这些州总共有多少城市. 一个联通分量算一个州,C保证为小数部分为0.5的实数. 解题思路:线段树维护每个位置上州和城市的个数,并查集维护哪些城市属于同一个州,并且要记录这些州上下范围.每次新建一条道路,要相应根据两个州的y坐标范围对线段树进行维护. #incl