1. 程式人生 > >101964C(二分+搜尋)

101964C(二分+搜尋)

題意給你一顆有n個節點的最小生成樹,每個節點都有一個顏色,1代表黑色,0代表白色,讓你從n個節點中選擇至少m個黑色節點。 求這m個黑色節點中任意兩個黑色節點的最遠距離的最小值。

分析 :首先,題目中的”使得最大值最小“這句話就非常符合二分的條件了。因此我們考慮對答案(兩個黑點的最遠的距離)進行二分。

現在就要考慮如何進行check。

對於每一個二分值k,我們考慮先用bfs遍歷整顆樹,然後利用bfs的性質(距離當前點的所有已bfs過且小於等於k的那些點,他們之間兩兩距離也小於等於k),我們可以用dfs去遍歷這些點集,判斷點集中的黑點的個數與需要選取的黑點個數m之間的關係即可(如果數量>=m,則右指標左移動;反之左指標右移)。

#include <iostream>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stdio.h>

using namespace std;

const int maxn =1000+10;

int n,m;
int a[maxn],vis[maxn];
vector<
int>G[maxn]; int dfs(int now,int dis,int fa,int k) { int sum=a[now]; if(dis>=k) return sum; for(int i=0; i<G[now].size(); i++) { int v=G[now][i]; if(!vis[v]||v==fa) continue; sum+=dfs(v,dis+1,now,k); } return sum; } int check
(int k)///本質為一個bfs { memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(1); vis[1]=1; while(!Q.empty()) { int u=Q.front(); Q.pop(); vis[u]=1;///表示已經訪問過 if(dfs(u,0,0,k)>=m)///獲取已訪問點的集合中的黑點個數 return 1; for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(!vis[v]) { Q.push(v); } } } return 0; } int main() { ///freopen("in.txt","r",stdin); while(scanf("%d %d",&n,&m)!=EOF) { for(int i=0; i<=n; i++) G[i].clear(); for(int i=1; i<=n; i++) scanf("%d",&a[i]); for(int i=0; i<n-1; i++) { int u,v; scanf("%d %d",&u,&v); G[u].push_back(v); G[v].push_back(u); } int l=0,r=n,mid; while(l<r) { mid=(l+r)/2; if(check(mid)) r=mid; else l=mid+1; } printf("%d\n",r); } return 0; }