题意:给你的一个包含n个数由1到n组成的数组,有m个操作,每个操作对应交换数组下标x和下标y,问经过任意次这些操作,最多能有多少下标满足(数组下标=对应下标的数)
Sample Input 1
Copy
5 2 5 3 1 4 2 1 3 5 4
Sample Output 1
Copy
2
If we perform the operation by choosing j=1, p becomes 1 3 5 4 2
, which is optimal, so the answer is 2.
思路:由于可以任意交换两位不限次数,那么只要是可以操作的下标集合,对应下标的数就一定可以到达集合任意位置。所以只要求出所有集合,然后判断下标和对应数是否在集合内。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <set> using namespace std; const int MAXN = 100005; const int inf = 0x3f3f3f3f; typedef long long LL; int a[MAXN]; struct node{ int from,to; }edge[MAXN*2]; int head[MAXN]; int vis[MAXN]; int bin[MAXN]; int cnt; void add(int u, int v) { edge[cnt].to=v; edge[cnt].from=head[u]; head[u]=cnt++; } int findx(int x) { if(bin[x]==x) return x; return bin[x]=findx(bin[x]); } void merge(int u, int v) { int fx=findx(u); int fy=findx(v); if(bin[fy]!=fx) bin[fy]=fx; } void dfs(int u) { vis[u]=1; for(int i=head[u];~i;i=edge[i].from) { int v=edge[i].to; if(!vis[v]) { bin[v]=cnt; dfs(v); } } } int main() { int n, m; cnt=0; memset(head, -1, sizeof(head)); memset(vis,0,sizeof(vis)); scanf("%d %d", &n, &m); for(int i=1;i<=n;++i) { scanf("%d", &a[i]); bin[i]=i; } for(int i=0;i<m;++i) { int x, y; scanf("%d %d", &x, &y); add(x,y); add(y,x); } int ans=0; cnt=1; for(int i=1;i<=n;++i) { if(!vis[i]) { bin[i]=cnt; dfs(i); cnt++; } if(bin[a[i]]==bin[i]) ans++; } printf("%d\n", ans); return 0; }