链接:Gym101964
题意:
给出一棵 n ( 1 ≤ n ≤ 100 ) n\,(1\le n\le 100) n(1≤n≤100)个结点的树,结点被涂成了黑色或者白色,要求找到最小的整数 k k k,使得能够选出 m m m个黑点,且黑点两两之间的最大距离 ≤ k \le k ≤k。
分析:
先预处理出所有黑点两两之间的距离;
对于一棵树,可以枚举选择了黑点后其 树的直径(即 黑点两两之间的最大距离),枚举选择直径端点 i , j i,j i,j,然后枚举剩余黑点 k k k,若 d i s t [ k ] [ i ] ≤ d i s t [ i ] [ j ] ∧ d i s t [ k ] [ j ] ≤ d i s t [ i ] [ j ] dist[k][i]\le dist[i][j]\land dist[k][j]\le dist[i][j] dist[k][i]≤dist[i][j]∧dist[k][j]≤dist[i][j],则该黑点可以选择。时间复杂度 O ( n 3 ) O(n^3) O(n3)。
代码:
#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;
}