101964C(二分+搜尋)
阿新 • • 發佈:2018-12-20
題意給你一顆有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;
}