icpc:problems:usaco21jan_dance_mooves_s
目录
problems | |
---|---|
名称 | Dance Mooves S |
题目编号 | USACO21JAN_S1 |
题目链接 | luogu.com.cn/… |
来源 | USACO |
算法分类 | 并查集, 图论 |
难易程度 | 一般般 |
Dance Mooves S
想法
由题目大意可以知道:
- 每分钟会交换两个位置。
- n*k轮会恢复原样。
假设现在有两个点A与B,A点在k次交换后从 x 走到了 y ,B点在k次交换后从 z 走到了 x。可以很明显的知道再经过k次交换后,B点会从x走到y。那A经过的点也一定会被B经过,B包含了A。
所以可以通过这个关系(起点与终点)来重新建立一张图,每个点会有一个出边与入边,出边指向经过k次交换后的终点,入边为经过k次交换后走到该点的点。这个图存在n个点,n条边,且每个点出度入度均为1,故这个图只有环,或自环。
在同一环内的牛,所有牛经过的位置互相均可以访问到。使用并查集来维护该环,并记录每头牛能经过的路径,最后汇总起来。
代码实现
#include<iostream> #include<set> #include<algorithm> using namespace std; const int N = 1e5+10; set<int>vis[N], ans[N]; int F[N], sit[N], n, k; int find(int x) { return x == F[x] ? x : F[x] = find(F[x]); } int main() { int x, y; cin >> n >> k; for(int i=1; i<=n; i++) { F[i] = i; sit[i] = i; vis[i].insert(i); } for(int i=1; i<=k; i++) { cin >> x >> y; swap(sit[x], sit[y]); vis[sit[x]].insert(y); vis[sit[y]].insert(x); } for(int i=1; i<=n; i++) { x = find(i); y = find(sit[i]); if(x != y) F[y] = x; } for(int i=1; i<=n; i++) { x = find(i); vis[x].insert(vis[i].begin(), vis[i].end()); } for(int i=1; i<=n; i++) cout << vis[find(i)].size() << '\n'; return 0; }
/app/www/public/data/pages/icpc/problems/usaco21jan_dance_mooves_s.txt · 最后更改: 2023/03/11 10:44 由 温婕莺