链接:Gym101964
题意:
给出一棵 个结点的树,结点被涂成了黑色或者白色,要求找到最小的整数 ,使得能够选出 个黑点,且黑点两两之间的最大距离 。
分析:
先预处理出所有黑点两两之间的距离;
对于一棵树,可以枚举选择了黑点后其 树的直径(即 黑点两两之间的最大距离),枚举选择直径端点 ,然后枚举剩余黑点 ,若 ,则该黑点可以选择。时间复杂度 。
代码:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=110;
int n,m,p[maxn];
struct edge
{
int u,v;
int next;
}e[maxn<<1];
int head[maxn],cnt;
void add_edge(int u,int v)
{
e[cnt]=edge{u,v,head[u]};
head[u]=cnt++;
e[cnt]=edge{v,u,head[v]};
head[v]=cnt++;
}
int dist[maxn][maxn];
void DFS(int root,int u,int pre)
{
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(v!=pre)
{
dist[root][v]=dist[v][root]=dist[root][u]+1;
DFS(root,v,u);
}
}
}
bool check(int i,int j)
{
int cnt=(i==j?1:2);
for(int k=1;k<=n;k++)
{
if(k==i||k==j||!p[k])
continue;
if(dist[k][i]<=dist[i][j]&&dist[k][j]<=dist[i][j])
cnt++;
}
if(cnt>=m)
return true;
else
return false;
}
int main()
{
memset(head,-1,sizeof(head));
cnt=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d %d",&u,&v);
add_edge(u,v);
}
for(int i=1;i<=n;i++)
DFS(i,i,-1);
int ans=INF;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(p[i]&&p[j]&&check(i,j))
ans=min(ans,dist[i][j]);
}
}
printf("%d",ans);
return 0;
}