1 条题解

  • 0
    @ 2025-10-22 17:50:13

    题解

    题目分析

    这是一道算法题目,需要根据具体题目要求进行求解。

    解题思路

    1. 问题分析

    • 仔细阅读题目描述,理解题目要求
    • 分析输入输出格式和约束条件
    • 确定需要使用的算法和数据结构

    2. 算法选择

    • 根据题目特点选择合适的算法
    • 考虑时间复杂度和空间复杂度
    • 确保算法能正确处理所有测试用例

    3. 实现要点

    • 注意边界条件的处理
    • 优化输入输出以提高效率
    • 确保代码的正确性和鲁棒性

    4. 调试和优化

    • 使用测试用例验证算法正确性
    • 分析性能瓶颈并进行优化
    • 确保代码能通过所有测试点

    注意事项

    • 仔细处理数据类型和精度问题
    • 注意数组越界和空指针问题
    • 确保算法的时间复杂度符合要求
    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=15,M=1e3+10,S=(1<<12)+10;
    int n,m;
    
    //邻接矩阵
    int a[N][N],ans=INT_MAX;
    
    //f[i][j]:表示当前最大深度为i,已经开发的宝藏屋集合为j的最小代价
    int f[N][S];
    
    //to[k]:表示点集k中的所有点最多扩展一层可以达到的的所有点(包括原来的)的集合
    //dis[k][x]:x属于k扩展最多一层能到的点集,dis[k][x]表示k状态扩展到x的最短道路长度,在求to的时候可以一并求出
    int to[S],dis[S][N];
    
    //can[j]:存储所有能转移到j状态的k
    //cst[j]:存储所有能转移到j状态的k的转移所需的最短道路长度之和(和can中一一对应)
    vector<int> can[S],cst[S];
    
    //非常直白的函数名啊...
    inline void get_to_dis()
    {
        //枚举k
        for(int k=0;k<(1<<n);k++)
        {
            to[k]=k;
            //枚举k中点
            for(int i=0;i<n;i++)
            {
                if(k&(1<<i))
                {
                    //枚举可以到达的点
                    for(int j=0;j<n;j++)
                    {
                        if(a[i][j]==0x3f3f3f3f)continue;
                        to[k]|=(1<<j);
                        dis[k][j]=min(dis[k][j],a[i][j]);
                    }
                }
            }
        }
        //时间复杂度为O((2^n)*n*n)
    }
    
    inline void get_can_cst()
    {
        //枚举j
        for(int j=0;j<(1<<n);j++)
        {
            //枚举k(必须是j的子集)
            for(int k=j;k;k=(k-1)&j)
            {
                //j又要为to[k]的子集(好绕啊...)
                if((j&to[k])==j)
                {
                    can[j].pb(k);
                    int sum=0,s=j^k;
                    for(int i=0;i<n;i++)
                    {
                        if(s&(1<<i))
                        {
                            sum+=dis[k][i];
                        }
                    }
                    cst[j].pb(sum);
                }
            }
        }
        //时间复杂度为O((2^n)*n*n)
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        memset(a,0x3f,sizeof(a));
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            //为了方便状压,我们都减1
            scanf("%d%d%d",&u,&v,&w);
            u--;
            v--;
            a[u][v]=min(a[u][v],w);
            a[v][u]=min(a[v][u],w);
        }
        memset(dis,0x3f,sizeof(dis));
        get_to_dis();
        get_can_cst();
        memset(f,0x3f,sizeof(f));
        //初始化
        for(int i=0;i<n;i++)
        {
            f[1][(1<<i)]=0;
        }
        //枚举层
        for(int i=2;i<=n;i++)
        {
            //枚举j
            for(int j=0;j<(1<<n);j++)
            {
                //枚举所有合法的k
                for(int t=0;t<(int)can[j].size();t++)
                {
                    int k=can[j][t];
                    f[i][j]=min(f[i][j],f[i-1][k]+(i-1)*cst[j][t]);
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            ans=min(ans,f[i][(1<<n)-1]);
        }
        printf("%d\n",ans);
        return 0;
    }
    
    • 1

    信息

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