题目:
http://codeforces.com/problemset/problem/659/E
题意:
给你一个图,现在要你给这个图里面的边定方向,使得入度为0的点最少。
分析:
对于一个连通块而言,如果里面存在一个环,那么必然所有点的入度都可以大于等于1
否则的话,就存在一个点的入度为0。
并查集:
#include <bits/stdc++.h>
using namespace std;
int n, m, u, v, fa[100005], a[100005];
int findfa(int x){return fa[x] == x? x : fa[x] = findfa(fa[x]);}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) fa[i] = i, a[i] =0;
for (int i = 1; i <= m; i++)
{
scanf("%d%d", &u, &v);
u = findfa(u), v = findfa(v);
if (u == v) a[u]++; //有环,标记一下
else
fa[u] = v,a[v]+=a[u];
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
if (findfa(i) == i) ans += a[i]==0? 1 : 0;
}
printf("%d
", ans);
return 0;
}
看到网上的题解大多数是dfs,这也更好理解:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
vector<int>a[N];
int flag;
bool vis[N];
void dfs(int u,int pre)
{
if(vis[u]){
flag=0;
return;
}
vis[u]=1;
for(int i=0;i<a[u].size();i++){
if(a[u][i]!=pre){
dfs(a[u][i],u);
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int x,y;
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
int ans=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
flag=1;
dfs(i,-1);
ans+=flag;
}
}
printf("%d
",ans);
return 0;
}