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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Redis的五种数据结构的底层实现原理

    Redis的五种数据结构的底层实现原理

    2021年4月10日
    119
  • 辛星解读mysql的用户管理

    辛星解读mysql的用户管理

    2022年1月30日
    44
  • java删除数组中指定元素_java学习中如何删除数组中的指定元素「建议收藏」

    java删除数组中指定元素_java学习中如何删除数组中的指定元素「建议收藏」java的api中,并没有提供删除数组中元素的方法。虽然数组是一个对象,不过并没有提供add()remove()或查找元素的方法。这就是为什么类似ArrayList和HashSet受欢迎的原因。不过,我们要感谢ApacheCommonsUtils,我们可以使用这个库的ArrayUtils类来轻易的删除数组中的元素。不过有一点需要注意,数组是在大小是固定的,这意味这我们删除元素后,并不会减少数组的…

    2022年8月11日
    10
  • 万能乘法速算法大全_玩转扑克牌亲子游戏大全收藏 孩子爱上数学 快速提升计算能力…「建议收藏」

    万能乘法速算法大全_玩转扑克牌亲子游戏大全收藏 孩子爱上数学 快速提升计算能力…「建议收藏」难得有时间陪孩子,莫老师教您几种扑克牌的玩法,给宅家生活提供一点小乐趣,轻松玩游戏的同时,增加乐趣,提升小孩的数感和反应能力,同时可以提高孩子的计算能力!电脑比较卡,花了一天的时间整理的游戏大全,好的东西记得收藏分享。认识扑克牌1、大、小王可以抽掉,或者指定当作数字几,也可以当作万能牌(抽到的人可以任意指定1-13中的任何一个数字)使用。把A、J、Q、K分别看作1点,11点、12点、13点,其余…

    2022年6月3日
    49
  • ubuntu安装中文输入法搜狗_中文输入法怎么调出来

    ubuntu安装中文输入法搜狗_中文输入法怎么调出来请注意命令中不应该的空格可能导致命令不合法!一、检查fctix框架首先,要安装中文输入法,必须要保证系统上有fctix。fctix是一个以GPL方式发布的输入法框架,安装fctix后可以为操作系统的桌面环境提供一个灵活的输入方案,解决在GNU/Linux环境下安装中文输入法的问题。win+a打开所有应用程序,找到Language…

    2022年9月26日
    4
  • 2021年美赛A题思路详解

    2021年美赛A题思路详解2021年数模美赛A题思路详解题目分析思路详解由于和队友思路不一致,导致最后我的思路只算了前两问,而后几问用了我认为离题的PCA(主成分分析)的方法,我的建模思路没有得到完全实现,总体情况很不满意,特此写下这篇文章。题目分析从题目前面所提供的背景知识可以看出,C指出分解速率与菌丝伸长速率成正相关关系,我队友认为是线性关系而我认为是对数近似的关系。第二长图给了一个正比的关系,但是坐标却很容易理解错。这个moisturetrde-off不是湿度耐受性(moisturenichewidth),更

    2022年6月9日
    89

发表回复

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

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