题意:现有n座城池,有n-1条道路将这些城池连成树,每座城池可以被两个国家占领,或者是无主,每个国家可以占领和自己城池相连的城池。问两个国家总城池树差最小值是多少。
分析:bfs跑A可以占据的所有城池,遇到B停下,假设可以占据a个城池,dfs跑B可以占据的所有城池,遇到A停下,假设可以占据b个城池,那么A可以占据n-b到a个城池,B可以占据n-a到b个城池。已知范围,枚举两个国家离n/2相差最小的结果。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; char a[N]; int vis[N]; vector<ll> edg[N]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++){ cin >> a[i]; } for (int i = 1; i < n; i++){ int x, y; cin >> x >> y; edg[x].push_back(y); edg[y].push_back(x); } queue<ll> q; for (int i = 1; i <= n; i++){ if (a[i] == 'A') { q.push(i); vis[i] = 1; } } while (q.size()){ ll u = q.front(); q.pop(); for (int v : edg[u]){ if (a[v] == 'B'){ continue; } if (vis[v]){ continue; } q.push(v); vis[v] = 1; } } ll sumA = 0; for (int i = 1; i <= n; i++) { sumA += vis[i]; } memset(vis, 0, sizeof(vis)); for (int i = 1; i <= n; i++) { if (a[i] == 'B') { q.push(i); vis[i] = 1; } } while (q.size()){ int u = q.front(); q.pop(); for (int v : edg[u]){ if (a[v] == 'A'){ continue; } if (vis[v]){ continue; } q.push(v); vis[v] = 1; } } ll sumB = 0; for (int i = 1; i <= n; i++){ sumB += vis[i]; } ll ans = 1e18; for (ll i = 0; i <= n; i++){ if (i <= sumA && n - i <= sumB){ ans = min(ans, abs(i - (n - i))); } } cout << ans << endl; return 0; }标签:城池,练习赛,edg,int,可以,占据,cin,牛客,131 From: https://blog.csdn.net/m0_74310050/article/details/143495100