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