AtCoder Regular Contest 097 D Equals

题目链接

题意:给你的一个包含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=1p 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;
}



猜你喜欢

转载自blog.csdn.net/fanhansheng/article/details/80295634
今日推荐