Codeforces Round #286 (Div. 1 B)

http://codeforces.com/contest/506/problem/B

Problem

一个图还有N个点,给M个关系 < a,b >,表示a必须要到达b,关系满足传递性,即a->b,b->c,则a->c。同时,a到b,b不一定要到a。问,最少要加多少条边,使得每个关系都成立。

Solution

对于一个N个点的图,由于边是有传递性的,不妨把N个点连成一个环,那么一定可以两两相互到达,但这不一定是最少的。对于一个弱联通图,含有n个点,如果它不存在环(是一个DAG),那么只需要n-1条边(想想看对DAG拓扑排序后,是不是n个点可以变成一条“链子“);如果它存在环,那么就把它变成一个环就好了,需要n条边。

算法如下:按照给定的M个关系,建图,a->b建一条边。dfs,判断每个弱联通图是否有环,然后统计答案。其中要用到,dfs判有向图环,并查集合并弱联通图..

My code

//Hello. I‘m Peter.
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define MAXN 100010
#define N 100100
#define M
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,m;
int nex[N],nexnum[N];
inline void init_nex(){
    for(int i=1;i<=n;i++){
        nex[i]=i;
        nexnum[i]=1;
    }
}
inline int findnex(int x){
    if(nex[x]!=x) nex[x]=findnex(nex[x]);
    return nex[x];
}
struct Edge{
    int from,to,next;
}edge[MAXN<<1];
int head[N],num_edge;
inline void init_Edge(){
    for(int i=1;i<=n;i++){
        head[i]=-1;
    }
    num_edge=0;
}
inline void add_Edge(int from,int to){
    int t=++num_edge;
    edge[t].from=from;
    edge[t].to=to;
    edge[t].next=head[from];
    head[from]=t;
}
int vis[N],loop[N];
bool ok;
inline void dfs(int now){
    if(!ok) return;
    vis[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].next){
        if(!ok) return;
        int to=edge[i].to;
        if(!vis[to]) dfs(to);
        else if(vis[to]==1){
            ok=false;
            return;
        }
        else if(vis[to]==-1) continue;
    }
    vis[now]=-1;
}
int main(){
    n=read(),m=read();
    init_nex();
    init_Edge();
    for(int i=1;i<=m;i++){
        int a=read(),b=read();
        add_Edge(a,b);
        int nex1=findnex(a);
        int nex2=findnex(b);
        if(nex1!=nex2){
            nex[nex1]=nex2;
            nexnum[nex2]+=nexnum[nex1];
        }
    }
    for(int i=1;i<=n;i++){
        int nex=findnex(i);
        if(loop[nex]||vis[i]) continue;
        ok=true;
        dfs(i);
        if(!ok) loop[nex]=true;
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        int nex=findnex(i);
        if(vis[nex]!=-2){
            vis[nex]=-2;
            if(loop[nex]) ans+=nexnum[nex];
            else ans+=nexnum[nex]-1;
        }
    }
    printf("%d\n",ans);
    return 0;
}
时间: 2024-10-25 17:59:05

Codeforces Round #286 (Div. 1 B)的相关文章

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 D 505D. Mr. Kitayuta&#39;s Technology【强连通分量,弱联通分量】

题目链接:http://codeforces.com/contest/505/problem/D 题目大意: 在一个图中,有n个顶点,给出m对数字(u,v)表示顶点u和顶点v必须直接或者间接相连,让你构造一个这样的图,输出最少需要多少条边. 分析: 毫无疑问,n个顶点的话,我们最多可以用n条边,使得n个顶点构成一个环,满足所有的情况(任意两点都是联通的),但是这并不一定是最少的边. 于是我们还需要找一个方法确定最少需要多少条边. 首先我们利用题目给出的点对建图,得到图G.对于G中的弱联通分量来说

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 Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st