GYM 101173 F.Free Figurines(贪心||并查集)

时间:2023-03-09 20:16:36
GYM 101173 F.Free Figurines(贪心||并查集)

原题链接

题意
俄罗斯套娃,给出一个初始状态和终止状态,问至少需要多少步操作才能实现状态转化

贪心做法
如果完全拆掉再重装,答案是p[i]和q[i]中不为0的值的个数。现在要求寻找最小步数,显然要减去一些多余的步数。如果初始的一些链的前端是终止的某一条链的连续的一部分,那么这条链就不用被拆开再连上,这样每一个长度为x的链对答案的贡献就是-2*(x-1),对每条链进行同样的操作之后就是答案

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define ull unsigned long long
#define LOCAL using namespace std;
const int maxn=1e5+;
const int inf=0x3f3f3f3f;
const int mod=1e9+; int p[maxn],q[maxn];
int n;
int main(){
scanf("%d",&n);
int vis[maxn];
int ans=;
for(int i=;i<=n;i++){
scanf("%d",&p[i]);
if(p[i]) vis[p[i]]=,ans++;
}
for(int i=;i<=n;i++){
scanf("%d",&q[i]);
if(q[i]) vis[q[i]]=,ans++;
} for(int i=;i<=n;i++){
if(!vis[i]){
int x=i;
while(p[x]&&q[x]&&p[x]==q[x]){
ans-=;
x=p[x];
}
}
}
printf("%d\n",ans);
return ;
}

并查集

只能进行2个操作:
1、 把一个没有父节点的节点作为一个 没有父节点和子节点的节点的子节点,代价为 1;

2、把一个没有父节点的节点的子节点去掉,代价为1;

那么只能对free的节点进行操作,所以当ai!=bi时,要先把ai拆掉,但必须先满足ai为free才能把i变成free,
同理把i插到bi上时也要满足bi节点为free(即该节点没有父节点)。

#include <iostream>
#include <cstdio> using namespace std;
typedef long long LL;
const int MAXN = 1e5 + ; int a[MAXN], b[MAXN], fa; int main()
{
#ifdef LOCAL
freopen("f.txt", "r", stdin);
//freopen("f.out", "w", stdout);
int T = ;
while(T--){
#endif // LOCAL
ios::sync_with_stdio(false); cin.tie(); int n, i, ans = , t;
cin >> n;
for(i = ; i <= n; i++){
cin >> a[i];
}
for(i = ; i <= n; i++){
cin >> b[i];
}
for(i = ; i <= n; i++){
if(a[i] == b[i]) continue;
if(a[i] != ){
ans++;
fa = a[i];
a[i] = ;
while(a[fa]){
t = fa;
fa = a[fa];
a[t] = ;
ans++;
}
}
}
for(i = ; i <= n; i++){
if(a[i] == b[i]) continue;
if(b[i] != ){
fa = a[b[i]];
if(fa){
a[b[i]] = ;
ans++;
}
else{
continue;
}
while(a[fa]){
t = fa;
fa = a[fa];
a[t] = ;
ans++;
}
}
}
for(i = ; i <= n; i++){
if(a[i] == b[i]) continue;
ans++;
}
cout << ans << endl;
return ;
}