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+10; const int inf=0x3f3f3f3f; const int mod=1e9+7; int p[maxn],q[maxn]; int n; int main(){ scanf("%d",&n); int vis[maxn]; int ans=0; for(int i=1;i<=n;i++){ scanf("%d",&p[i]); if(p[i]) vis[p[i]]=1,ans++; } for(int i=1;i<=n;i++){ scanf("%d",&q[i]); if(q[i]) vis[q[i]]=1,ans++; } for(int i=1;i<=n;i++){ if(!vis[i]){ int x=i; while(p[x]&&q[x]&&p[x]==q[x]){ ans-=2; x=p[x]; } } } printf("%d\n",ans); return 0; }
并查集
只能进行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 + 8; int a[MAXN], b[MAXN], fa; int main() { #ifdef LOCAL freopen("f.txt", "r", stdin); //freopen("f.out", "w", stdout); int T = 4; while(T--){ #endif // LOCAL ios::sync_with_stdio(false); cin.tie(0); int n, i, ans = 0, t; cin >> n; for(i = 1; i <= n; i++){ cin >> a[i]; } for(i = 1; i <= n; i++){ cin >> b[i]; } for(i = 1; i <= n; i++){ if(a[i] == b[i]) continue; if(a[i] != 0){ ans++; fa = a[i]; a[i] = 0; while(a[fa]){ t = fa; fa = a[fa]; a[t] = 0; ans++; } } } for(i = 1; i <= n; i++){ if(a[i] == b[i]) continue; if(b[i] != 0){ fa = a[b[i]]; if(fa){ a[b[i]] = 0; ans++; } else{ continue; } while(a[fa]){ t = fa; fa = a[fa]; a[t] = 0; ans++; } } } for(i = 1; i <= n; i++){ if(a[i] == b[i]) continue; ans++; } cout << ans << endl; return 0; }