貝殼找房魔法師顧問[並查集+DAG判斷]

題目連接【https://nanti.jisuanke.com/t/27647】c++

//計蒜客2018複賽D題,想簡單了。函數

題解:spa

  題目是中文的,再也不贅述。code

題解:blog

  分爲三種狀況:一、兩個字符串都不能變:這種狀況最簡單,直接暴力判斷兩個支付穿是否相同便可。排序

         二、兩個字符串都能變:把上下對應位置不一樣的點連無向邊(由於均可以改變),創建了一個深林,這裏用並查集實現,順便維護每一個聯塊的大小,對於每一個聯通塊來講,要把這些點都變成同樣的,最少要變換(size-1)次,即選出一個點,把其餘的點都變成被選中的點。字符串

         三、一個能變,一個不能變:這種狀況最複雜。同第二種狀況,這裏須要建圖,創建單向邊,(只能由V變成C),對於每個聯通塊,咱們判斷該聯通塊是否是DAG,若是是,那麼只須要改變(size-1)次就好了。若是不是DAG,那麼聯通塊中存在環,那麼最少要變(size)次,只須要把這些點鏈接成有向環就能夠了,保證了兩兩能夠互達。it

 

只是思路、具體細節和緣由須要本身思考。歡迎斧正。QQ2421780543。class

 

#include<bits/stdc++.h>
using namespace std; typedef long long LL; const int maxn = 1e5 + 15; LL a[maxn], b[maxn]; char s[15], t[15]; //-----------------------並查集
int fa[maxn], val[maxn]; void init() { for(int i = 1; i <= 100000; i++) fa[i] = i, val[i] = 1; } int Find(int u) { if(fa[u] == u) return u; return fa[u] = Find(fa[u]); } void Unit(int u, int v) { int x = Find(u); int y = Find(v); if(x != y) { fa[x] = y; val[y] += val[x]; val[x] = 0; } } //-------------------------EDGE
int rd[maxn], vis[maxn], cnt = 0;; vector<int>vt[maxn]; map<int, int>mp; queue<int>que; struct Edge { int to, next; Edge(int to = 0, int next = 0): to(to), next(next) {} } E[maxn * 4]; int head[maxn], tot; void Init_Edge() { for(int i = 1; i <= 100000; i++) head[i] = -1; tot = 0; } void Add_Edge(int u, int v) { E[tot] = Edge(v, head[u]); head[u] = tot++; } //--------------------------主函數
int main () { int n, fg1 = 0, fg2 = 0; scanf("%d", &n); scanf("%s", s); for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); scanf("%s", t); for(int i = 1; i <= n; i++) scanf("%lld", &b[i]); if(s[0] == 'V') fg1 = 1; if(t[0] == 'V') fg2 = 1; if((!fg1) && (!fg2))//都不能更改
 { bool ans = true; for(int i = 1; i <= n && ans; i++) if(a[i] != b[i]) ans = false; if(ans) printf("0\n"); else printf("-1\n"); } else if(fg1 && fg2)//均可以更改
 { init(); for(int i = 1; i <= n; i++) { if(a[i] != b[i]) Unit(a[i], b[i]); } int num = 0; for(int i = 1; i <= 100000; i++) { Find(i); if(fa[i] == i) num += val[i] - 1; } printf("%d\n", num); } else //只能改一個
 { init(); Init_Edge(); for(int i = 1; i <= n; i++) if(a[i] != b[i]) { Unit(a[i], b[i]); Add_Edge(a[i], b[i]); rd[b[i]] ++; vis[a[i]] = vis[b[i]] = 1; } for(int i = 1; i <= 100000; i++)//提取聯通塊
 { if(vis[i]) { int t = Find(i); if(mp[t]) { int tmp = mp[t]; vt[tmp].push_back(i); } else { mp[t] = ++cnt; vt[cnt].push_back(i); } } } int num = 0; for(int i = 1; i <= cnt; i++)//拓撲排序,判斷DAG
 { int len = vt[i].size(); for(int j = 0; j < len; j++) { int tmp = vt[i][j]; if(rd[tmp] == 0) que.push(tmp); } int tmp = 0; while(!que.empty()) { int u = que.front(); que.pop(); tmp++; for(int j = head[u]; j != -1; j = E[j].next) { int v = E[j].to; rd[v]--; if(rd[v] == 0) que.push(v); } } if(tmp == len) num += len - 1; else num += len; } printf("%d\n", num); } return 0; }
相關文章
相關標籤/搜索