Codeforces Round #286 div.2 D 505D. Mr. Kitayuta's Technology【强连通分量,弱联通分量】

题目链接:http://codeforces.com/contest/505/problem/D

题目大意:

在一个图中,有n个顶点,给出m对数字(u,v)表示顶点u和顶点v必须直接或者间接相连,让你构造一个这样的图,输出最少需要多少条边。

分析:

毫无疑问,n个顶点的话,我们最多可以用n条边,使得n个顶点构成一个环,满足所有的情况(任意两点都是联通的),但是这并不一定是最少的边。

于是我们还需要找一个方法确定最少需要多少条边。

首先我们利用题目给出的点对建图,得到图G。对于G中的弱联通分量来说,分两种情况讨论:

1.这个弱联通分量中没有环。那么我们能够利用拓扑排序将这个图变成一条链子,假设这个分量中有n1个顶点,那么毫无疑问,所需要的边数为n1-1。

2.这个弱联通分量中有环。假设这个分量中有n2个顶点,那么我们可以用n2条边,将这个n2个顶点构成一个环,

有了上述分析,那么我们现在的工作就是需要判断每个弱联通分量里面有没有环即可。判断环的方法呢,那就是检测这个点所在的强连通分量里点的个数是否等于1,如果大于1,那么说明这个分量中有环,如果等于1,那么说明这个分量中没有环。

代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define N 100010
vector<int> g[N];
vector<int> rg[N];
vector<int> vs;
bool used[N];
int cmp[N];
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]=1;
    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]=1;
    cmp[v]=k;
    for(int i=0;i<rg[v].size();i++)
        if(!used[rg[v][i]])
            rdfs(rg[v][i],k);
}
int scc()
{
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<n;v++)
        if(!used[v])
            dfs(v);
    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++);
    return k;
}
int cmpsize[N];
bool dfs2(int v)
{
    used[v]=1;
    bool ans=(cmpsize[cmp[v]]==1);
    for(int i=0;i<g[v].size();i++)
    {
        if(!used[g[v][i]]) ans &= (dfs2(g[v][i])==1);
    }
    for(int i=0;i<rg[v].size();i++)
    {
        if(!used[rg[v][i]]) ans &= (dfs2(rg[v][i])==1);
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(cmpsize,0,sizeof(cmpsize));
        for(int i=0;i<n;i++)
            rg[i].clear(),g[i].clear();

        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u-1,v-1);
        }
        scc();
        memset(used,0,sizeof(used));
        for(int i=0;i<n;i++)
            cmpsize[cmp[i]]++;
        int ans=n;
        for(int i=0;i<n;i++)
        {
            if(!used[i])
                ans -= dfs2(i);
        }
        cout<<ans<<endl;
    }
    return 0;
}

Codeforces Round #286 div.2 D 505D. Mr. Kitayuta's Technology【强连通分量,弱联通分量】

时间: 2024-12-09 14:32:38

Codeforces Round #286 div.2 D 505D. Mr. Kitayuta's Technology【强连通分量,弱联通分量】的相关文章

Codeforces Round #286 div.1 D 506D D. Mr. Kitayuta&#39;s Colorful Graph【并查集】

题目链接:http://codeforces.com/problemset/problem/506/D 题目大意: 给出n个顶点,m条边,每条边上有一个数字,代表某个颜色.不同数字代表不同的颜色.有很多个询问,每个询问问有多少条纯种颜色的路径使得某两个点联通. 分析: 这个题一看就想用并查集来搞,每种颜色用一个并查集处理.对于输入的每条边,我们只需要将这两个点在这条边的颜色对应的并查集中合并就好了.查询的时候,我们只需要检测这两个点在多少个颜色对应的并查集中是在统一集合中的,那么就有多少条纯种颜

Codeforces Round #286 (Div. 2)B. Mr. Kitayuta&#39;s Colorful Graph(dfs,暴力)

数据规模小,所以就暴力枚举每一种颜色的边就行了. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm>

Codeforces Round #286 (Div. 2)A. Mr. Kitayuta&#39;s Gift(暴力,string的应用)

由于字符串的长度很短,所以就暴力枚举每一个空每一个字母,出现行的就输出.这么简单的思路我居然没想到,临场想了很多,以为有什么技巧,越想越迷...是思维方式有问题,遇到问题先分析最简单粗暴的办法,然后一步一步的优化,不能盲目的想. 这道题要AC的快需要熟悉string的各种用法.这里做个简单总结:C++中string的常见用法. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstrin

Codeforces Round #286 (Div. 2) B. Mr. Kitayuta&#39;s Colorful Graph +foyd算法的应用

B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Mr. Kitayuta has just bought an undirected graph consisting of n vertices and m edges. The vertices of the g

水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta&#39;s Gift

题目传送门 1 /* 2 水题:vector容器实现插入操作,暴力进行判断是否为回文串 3 */ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <cstring> 8 #include <string> 9 #include <vector> 10 using namespace std; 11 12 const int MAXN

DFS/并查集 Codeforces Round #286 (Div. 2) B - Mr. Kitayuta&#39;s Colorful Graph

题目传送门 1 /* 2 题意:两点之间有不同颜色的线连通,问两点间单一颜色连通的路径有几条 3 DFS:暴力每个颜色,以u走到v为结束标志,累加条数 4 注意:无向图 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <algorithm> 9 #include <cstring> 10 #include <string> 11 #include <vector> 1

Codeforces Round #286 (Div. 1) D. Mr. Kitayuta&#39;s Colorful Graph

D - Mr. Kitayuta's Colorful Graph 思路:我是暴力搞过去没有将答案离线,感觉将答案的离线的方法很巧妙.. 对于一个不大于sqrt(n) 的块,我们n^2暴力枚举, 对于大于sqrt(n)的块,我们暴力枚举答案. 这样就能做到严格sqrt(n) * n #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #defin

CodeForces 506B/505D Mr. Kitayuta&#39;s Technology

Portal:http://codeforces.com/problemset/problem/506/B http://codeforces.com/problemset/problem/505/D 好题 给n个城市,m条有向边,求出最少的有向边使得其构成的图与原图等势 对于每个连通分量: 如果无环,那么只需要需要n-1条边完成联通 如果有环,则只需要n条边完成联通 所以这题只要判下连通分量,再看有几个连通分量有环即可 解法一:无向图遍历求强连通分量再把强连通分量所代表的联通分量dfs判环,如

Codeforce 505D - Mr. Kitayuta&#39;s Technology 弱联通分量+拓扑排序

对于有向图M,若将其所有的边转化为无向边,则得到其基图M',若M'是联通的,则称有向图M是弱联通. 对于有向图M,若图中任意两点u,v(u != v)均满足u到v可达,v到u可达,则称此图为强联通. 根据以上定义显然可知,强联通图一定也满足弱联通. 此题首先我们需要找到其所有的弱联通分量. 对于每一个弱联通分量,设此弱联通分量内点的个数为ans,如果此联通分量无环,则需要的边数为ans-1,若有环则为ans. 太挫了,这种题都不会了,怎么变黄!!! #include <algorithm> #