Gym101964 -C Tree(树的直径)

链接Gym101964

题意:

给出一棵 n ( 1 n 100 ) n\,(1\le n\le 100) 个结点的树,结点被涂成了黑色或者白色,要求找到最小的整数 k k ,使得能够选出 m m 个黑点,且黑点两两之间的最大距离 k \le k



分析:

先预处理出所有黑点两两之间的距离;

对于一棵树,可以枚举选择了黑点后其 树的直径(即 黑点两两之间的最大距离),枚举选择直径端点 i , j i,j ,然后枚举剩余黑点 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] ,则该黑点可以选择。时间复杂度 O ( n 3 ) O(n^3)



代码:

#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;
}
发布了214 篇原创文章 · 获赞 40 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/101421479