1 条题解

  • 0
    @ 2025-5-8 20:53:54

    题目描述

    奶牛们最近在制作电影,它们准备玩一个著名游戏“凯文·贝肯的六度分隔理论”的变体。

    游戏规则如下:每头奶牛与它自己的分隔度为零。如果两头不同的奶牛共同出演了一部电影,那么它们之间的分隔度为 1 度。如果两头奶牛没有共同出演电影,但它们都与第三头奶牛共同出演过电影,那么它们之间的分隔度为 2 度(计算方式为:先到共同出演的奶牛为 1 度,再到另一头奶牛又 1 度)。以此类推。

    N2 <= N <= 300)头奶牛,它们想找出与其他所有奶牛的平均分隔度最小的奶牛(不包括它自己)。奶牛们制作了 M1 <= M <= 10000)部电影,并且保证任意两头奶牛之间都存在某种关系路径。

    输入

    • 第一行:两个用空格分隔的整数 NM
    • 第 2 行到第 M + 1 行:每行包含一组用空格分隔的整数,描述了出演同一部电影的奶牛。每行的第一个整数是出演该电影的奶牛数量 Mi,后续 Mi 个整数表示出演该电影的奶牛编号。

    输出

    • 第一行:一个整数,表示所有奶牛中与其他奶牛的平均分隔度最小的奶牛的平均分隔度乘以 100 的结果。

    示例输入

    4 2
    3 1 2 3
    2 3 4
    

    示例输出

    100
    

    提示

    [奶牛 3 与其他所有奶牛都共同出演过电影,所以它与其他奶牛的分隔度分别为 1, 1, 1,平均分隔度为 1.00。]

    来源

    USACO 2003 年 3 月 Orange 组

    题意分析

    奶牛们玩一个“六度分隔理论”的变体游戏。在这个游戏里,每头奶牛与自身的分隔度是 0 度。若两头奶牛共同出演过一部电影,它们的分隔度为 1 度;若两头奶牛没一起演过电影,但都和第三头奶牛合作过,它们的分隔度为 2 度,依此类推。现在已知有 N 头奶牛,它们一共制作了 M 部电影,且任意两头奶牛之间都存在关系路径。需要找出与其他所有奶牛平均分隔度最小的奶牛,最后输出这个最小平均分隔度乘以 100 的结果。

    解题思路

    1. 构建图的邻接矩阵
      • 用二维数组 dis 来表示奶牛之间的分隔度,初始时将所有奶牛之间的分隔度设为无穷大 INF,而每头奶牛与自身的分隔度设为 0。
      • 依据输入的每部电影的参演奶牛信息,把共同出演同一部电影的奶牛之间的分隔度设为 1。
    2. 使用 Floyd-Warshall 算法:借助 Floyd-Warshall 算法计算出任意两头奶牛之间的最短分隔度。该算法的核心思想是通过动态规划,不断尝试经过中间节点来更新两点之间的最短路径。
    3. 计算平均分隔度并找出最小值
      • 针对每头奶牛,计算它与其他所有奶牛的分隔度之和。
      • 把分隔度之和除以 n - 1(排除自身)得到平均分隔度。
      • 找出所有奶牛中平均分隔度的最小值。
    4. 输出结果:将最小平均分隔度乘以 100 后输出。

    算法标签

    • 图论:把奶牛看作图的节点,奶牛之间的共同出演关系看作边,通过图的邻接矩阵来存储和处理节点间的关系。
    • Floyd-Warshall 算法:用于求解图中任意两点之间的最短路径,时间复杂度为 O(V3)O(V^3),其中 VV 是图中节点的数量。
    • 动态规划:Floyd-Warshall 算法基于动态规划的思想,通过不断更新状态来得到最优解。

    代码实现

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int INF=1000000009;
    int n,m,amount,a[700],dis[700][700];
    int ans=INF;
     
    void floyd()
    {
        //memset(dis,INF,sizeof(dis));
        for(int i=1;i<=n;i++)
            dis[i][i]=0;
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            if(dis[i][j]<INF&&dis[k][j]<INF)
            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
     
     
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(dis,INF,sizeof(dis));///要在这个地方memset;
        while(m--)
        {
            scanf("%d",&amount);
            for(int i=1;i<=amount;i++)
                scanf("%d",&a[i]);
                for(int i=1;i<=amount;i++)
                    for(int j=1;j<i;j++)
                dis[a[i]][a[j]]=dis[a[j]][a[i]]=1;
        }
        floyd();
        for(int i=1;i<=n;i++)
        {
            int sum=0;
            for(int j=1;j<=n;j++)
                if(i!=j)
            {
                sum=sum+dis[i][j];
            }
            ans=min(ans,sum);
            //printf("ans:%d\n",ans);
        }
        printf("%d\n",(ans*100)/(n-1));
    }
    
    • 1

    信息

    ID
    1140
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者