持续创作,加速成长!这是我参与「掘金日新计划 · 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;
}