GYM 101173 F.Free Figurines(貪心||並查集)
阿新 • • 發佈:2017-08-01
efi can 初始 typedef 多余 一個 class type pri
原題鏈接
題意:
俄羅斯套娃,給出一個初始狀態和終止狀態,問至少需要多少步操作才能實現狀態轉化
貪心做法
如果完全拆掉再重裝,答案是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; }
GYM 101173 F.Free Figurines(貪心||並查集)