时间:2016-04-01 19:27:59 星期五
题目编号:[2016-04-01][codeforces][659E][New Reform]
题目大意:给定n个城市,m条路,每条路连接两个城市,每两个城市最多只有一条路连接,现在把路改成单项的,问最少会出现几个孤立的城市(没有城市到达它),
分析:
- 在一个联通分支中,如果边数为n - 1,那么这个图就是树,树上除了根节点,其他节点都可达,如果边数大于n-1,那么至少会出现一个环,只要选的点在环上,那么所有的点都可达
- 题目不止一个联通分支,
- 第一个方法T了,用并查集处理整个图,从每个联通分支的父节点出发,求边数,更新最终答案–>这个T了
- 用并查集存图,扫一遍所有节点,更新所有节点的度数和到父节点上,则边数等于总度数/2,更新每个联通分支的节点数到父节点上
#include <cstring>#include <cstdio>using namespace std;const int maxn = 1E5 + 10;int fa[maxn],d[maxn],cnt[maxn];inline void ini(int n){ for(int i = 0; i <= n ;++i){ fa[i] = i; } memset(d,0,sizeof(int) * (n + 1)); memset(cnt,0,sizeof(int) * (n + 1));}int fnd(int x){ return fa[x] == x ? x:fa[x] = fnd(fa[x]);}inline void uni(int x,int y){ fa[fnd(x)] = fnd(y);}int main(){ int n,m,a,b; scanf("%d%d",&n,&m); ini(n); for(int i = 0;i < m ; ++i){ scanf("%d%d",&a,&b); ++d[a];++d[b]; uni(a,b); } int f; for(int i = 1;i <= n ; ++i){ f = fnd(i); ++cnt[f]; if(f != i) d[f] += d[i]; } int ans = 0; for(int i = 1; i <= n ; ++i){ if(fa[i] == i && cnt[i] == d[i] / 2 + 1){ ++ans; } } printf("%d\n",ans); return 0;}