2019河北省大学生程序设计竞赛:J.舔狗

194 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情

2019河北省大学生程序设计竞赛——J-舔狗

J-舔狗

题目描述

“舔狗舔狗, > 舔到最后, > 一无所有。” 有 n 只舔狗,每只舔狗的心中都有自己朝思暮想的一位。 每个人虽然受到了一万次拒绝,还毅然第一万零一次鼓起勇气。 作为一个不食人间烟火的算法设计师,你早已看破红尘。但是,人世间的苦难仍让你挂念。看到众生在单恋中苦苦坚持,你决定普度众生,给大家找到一个最好的结局,让一无所有的舔狗尽量地少,让每个人都尽量能和自己喜欢的或喜欢自己的人修成正果。 也就是说,你需要给这 n 只舔狗配对,对于舔狗 i,他可以和他朝思暮想的人 aia_{i}ai​ 配对。另外,喜欢 i 的其他舔狗也可以和他配对。你需要让没有被配对的舔狗尽量少。

输入描述:

第一行一个 n,表示舔狗个数。
第二行 n 个数字,第 i 个数字表示第 i只舔狗的朝思暮想的一位的编号 ai。
2≤n≤10^6

输出描述:

第一行一个数字,表示一无所有的舔狗的最小数量。    

输入

10
3 1 8 6 10 1 4 1 6 1

输出

0

问题解析

贪心+拓扑排序。

可以把关系网看作一张有向图,每个点的入度就是那个人的舔狗。那么如果想要配对的人最多,就应该从没有舔狗的人开始配对,因为如果这个人没有舔狗,那么只要他喜欢的人和别人配对了,那他就只能打光棍了。

这一点就和拓扑排序一样了。我们先从没有舔狗的点x开始,和他喜欢的a[x]配对。那么a[x]喜欢的人就少了个舔狗,入度--,如果这个人没有舔狗了,就把它也入队。

至于剩下的人,我们可以看他们是否组成环,如果组成环了,那么其中偶数个数的人还可以继续配对,这一点可以用并查集做到。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include <random>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<fstream>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#include<bitset>#pragma GCC optimize(2)
#pragma GCC optimize(3)#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;
​
int n,a[N],fa[N],mysize[N];
bool st[N];
unordered_map<int, int>mymap;
int find(int x)
{
    if(x!=fa[x])
        fa[x]=find(fa[x]);
    return fa[x];
}
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        fa[i]=i;
        mysize[i]=1;
        mymap[a[i]]++;
    }
    queue<int>que;
    for (int i = 1; i <= n; i++)
    {
        if (mymap[i] == 0)
        {
            que.push(i);
        }
    }
    int res = 0;
    while (!que.empty())
    {
        int x = que.front();
        que.pop();
        if(st[x]||st[a[x]])continue;
        st[x]=st[a[x]]=true;
        res+=2;
        mymap[a[a[x]]]--;
        if(mymap[a[a[x]]]==0)que.push(a[a[x]]);
    }
    for(int i=1;i<=n;i++)
    {
        if(!st[i]&&!st[a[i]])
        {
            int x=find(i),y=find(a[i]);
            if(x!=y)
            {
                fa[y]=x;
                mysize[x]+=mysize[y];
                mysize[y]=mysize[x];
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        int x=find(i);
        if(!st[x])
        {
            res+=mysize[x]/2*2;
            st[x]=true;
        }
    }
    cout<<n-res;
}
​
signed main()
{
​
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    //cin >> t;
​
    while (t--)
    {
        solve();
    }
    return 0;
}