题意:现有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;
}