NOIPD2T2 – 宝藏 题解

NOIPD2T2 – 宝藏 题解

大家好,又见面了,我是你们的朋友全栈君。

填坑,史前巨坑。
题意:对于一张图,确定一个点为根,构建一个生成树。求代价最小值。
代价的定义:“树中每一条边的权值与较浅点深度的乘积”之和。
考场上没有想清楚就草草码了一个Prim然后交了,但是因为你代价和深度有关,所以贪心地Prim是错误的。
因为 $N$ 很小,这应当引导我们想到状压。(套路)
答案与深度有关,所以我们可以令 $f[i][S]$ 为最深点深度为 $i$,已选点的集合为 $S$ 时的最小答案。
枚举 $p$ 为 $S$ 的补集的子集,那么
$$f[i][S|p]=min(f[i-1][S]+cost[p])$$
状压可以把集合压成二进制数。(套路 again)
枚举集合补集的子集怎么做?
可以用树状数组中出现的 $lowbit(i)=i\&(-i)$。(小技巧)
如何求 $cost$ 呢?同样用 $lowbit$。
然后我们就可以欢快的转移状态了。特判一下 $N=1$。
代码:

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define reg register
#define cmin(_,__) ((_)>(__)?(_)=(__),1:0)
#define cmax(_,__) ((_)<(__)?(_)=(__),1:0)
#define dmin(_,__) ((_)<(__)?(_):(__))
#define dmax(_,__) ((_)>(__)?(_):(__))
#define Abs(_) ((_)>0?(_):-(_))
#define lowbit(_) ((_)&-(_))
using namespace std;
const long long Inf=1ll<<29;
int N,M,tot,pos[15],two[5005],used[5005];
long long f[15][5005],map[15][15],res=Inf,V[15],g[5005];
int main(){
    scanf("%d%d",&N,&M);
    if(N==1){
        puts("0");
        return 0;
    }
    for(reg int i=0;i<N;i++)
        for(reg int j=0;j<N;j++)
            map[i][j]=Inf;
    for(reg int i=1,u,v,w;i<=M;i++){
        scanf("%d%d%d",&u,&v,&w);u--,v--;
        cmin(map[u][v],w);map[v][u]=map[u][v];
    }
    for(reg int i=0;i<N;i++)
        two[1<<i]=i;
    for(reg int i=0;i<=N;i++)
        for(reg int S=0;S<(1<<N);S++)
            f[i][S]=Inf;
    for(reg int i=0;i<N;i++)
        f[0][1<<i]=0;
    for(reg int i=0;i<N;i++){
        for(reg int S=0;S<(1<<N);S++){
            /* 补集 */
            tot=0;
            for(reg int j=0;j<N;j++){
                if(!(S&(1<<j))){
                    V[tot]=Inf;pos[tot]=1<<j;
                    for(reg int x=S;x;x-=lowbit(x))
                        cmin(V[tot],map[j][two[lowbit(x)]]*(i+1));
                    tot++;
                }
            }
            g[0]=used[0]=0;
            for(reg int j=1;j<(1<<tot);j++){
                g[j]=g[j-lowbit(j)]+V[two[lowbit(j)]];
                used[j]=used[j-lowbit(j)]|pos[two[lowbit(j)]];
                cmin(f[i+1][S|used[j]],f[i][S]+g[j]);
            }
        }
    }
    for(reg int i=1;i<=N;i++)
        cmin(res,f[i][(1<<N)-1]);
    printf("%lld\n",res);
    return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107507.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月2日 下午9:35
下一篇 2022年4月2日 下午9:35


相关推荐

  • pycharm关联git

    pycharm关联git1 打开 pycharm gt File gt Settings 点击 Test 后 出现弹框 5 点击 OK 此时 Pycharm 已关联 git 路径成功 2 pycharm 关联 gitlab 仓库地址依次点击下图中的 1 gt 2 gt 3 标记处 会出现 2 中的弹框 2 填写如下 在 URL 处 填写 gitlab 拉取代码的地址 点击 Test 后 会出现一个弹框 需要你填写用户名和密码 千万不要填错了欧 完成后就可以填入 Directory 处的地址 你拉取的代码要放到哪个文件

    2026年3月27日
    3
  • 完整教程:Claude Code 安装 & IDE 集成教程

    完整教程:Claude Code 安装 & IDE 集成教程

    2026年3月15日
    6
  • 河北对口计算机专业一分一档6,2019河北高考一分一档表成绩排名(理科)[通俗易懂]

    河北对口计算机专业一分一档6,2019河北高考一分一档表成绩排名(理科)[通俗易懂]2019年河北省普通高校招生文理科一分一档统计表2019河北高考一分一档统计表公布2019河北高考一分一档统计表公布22019河北高考一分一档统计表公布32019河北高考一分一档统计表公布42019河北高考一分一档统计表公布52019河北高考一分一档统计表公布62019河北高考一分一档统计表公布72019河北高考一分一档统计表公布82019河北高考一分一档统计表公布92019河北高考一分一档统计表…

    2022年7月13日
    51
  • RocketMQ原理解析

    RocketMQ原理解析1 NameServer 名称服务 NameServer 是没有状态的 即 NameServer 中的 Broker 和 topic 等状态信息 通过其他角色上报获取 都是保存在内存中的 不会持久化存储 可通过配置实现 集群可以横向扩展 主要功能如下 a 接收 Broker master 和 slave 启动时的注册路由信息 b 为 producer 和 consumer 提供路由服务 即通过 topic 名字获取所

    2025年6月26日
    4
  • 1到n阶乘算法的改进「建议收藏」

    1到n阶乘算法的改进「建议收藏」1到n阶乘算法的改进之前用到过好几次了,但总是很长时间不用就会忘了,所以这次直接把它扔进来了。之前总是喜欢用双层循环,其实一个单层循环足以,下面将用Python和C++两种语言进行展示C++:#include<iostream>usingnamespacestd;intmain(){ intsum=0,tmp; for(inti=1;i<=10;i++) { tmp=1; for(intj=1;j<=i;j++) tmp*=j; sum

    2022年7月24日
    15
  • 类加载器的作用

    类加载器的作用深入探讨 Java 类加载器成富 软件工程师 IBM 中国软件开发中心成富任职于 IBM 中国软件开发中心 目前在 Lotus 部门从事 IBMMashupCen 的开发工作 他毕业于北京大学信息科学技术学院 获得计算机软件与理论专业硕士学位 他的个人网站是 nbsp http www cheng fu com 简介 nbsp 类加载器 classloader

    2025年9月18日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号