zoukankan      html  css  js  c++  java
  • [tyvj2054] 四叶草魔杖 (最小生成树 状压dp)

    传送门

    Background

    陶醉在彩虹光芒笼罩的美景之中,探险队员们不知不觉已经穿过了七色虹,到达了目的地,面前出现了一座城堡和小溪田园,城堡前的木牌上写着“Poetic Island”。
    “这一定就是另外两位护法的所在地了……我们快进去吧!”
    探险队员们快步进入了城堡,城堡大厅的羊毛沙发上坐着两个人。
    “你们是Nescafe的护法吧?”
    “是的哦~ 我们就是圣剑护法rainbow和魔杖护法freda~ 你们来这里做什么呢~”
    “我们是来拜访圣主和四位护法的……”
    “可是圣主applepi已经前往超自然之界的学校(Preternatural Kingdom University,简称PKU)修炼魔法了,要想见到他,必须开启Nescafe之塔与超自然之界的通道。但是圣主规定,开启通道的方法不能告诉任何外人。我只能提示你们,开启通道的钥匙就与四位护法有关T_T”
    探险队员环视四周,突然,其中一人的目光停留在了魔杖之上。“hoho~ 魔杖!传说中开启异时空通道的钥匙不就叫四叶草魔杖吗?四叶草有力量、信心、希望和幸运四片叶子,护法恰好有神刀、飞箭、圣剑、魔杖四位!aha~我找到答案了!”
    “好吧,那我们就满足你们的愿望~”

    Description

    魔杖护法Freda融合了四件武器,于是魔杖顶端缓缓地生出了一棵四叶草,四片叶子幻发着淡淡的七色光。圣剑护法rainbow取出了一个圆盘,圆盘上镶嵌着N颗宝石,编号为0~N-1。第i颗宝石的能量是Ai。如果Ai>0,表示这颗宝石能量过高,需要把Ai的能量传给其它宝石;如果Ai<0,表示这颗宝石的能量过低,需要从其它宝石处获取-Ai的能量。保证∑Ai =0。只有当所有宝石的能量均相同时,把四叶草魔杖插入圆盘中央,才能开启超自然之界的通道。
    不过,只有M对宝石之间可以互相传递能量,其中第i对宝石之间无论传递多少能量,都要花费Ti的代价。探险队员们想知道,最少需要花费多少代价才能使所有宝石的能量都相同?

    Input

    第一行两个整数N、M。
    第二行N个整数Ai。
    接下来M行每行三个整数pi,qi,Ti,表示在编号为pi和qi的宝石之间传递能量需要花费Ti的代价。数据保证每对pi、qi最多出现一次。

    Output

    输出一个整数表示答案。无解输出Impossible。

    Sample Input

    3 3
    50 -20 -30
    0 1 10
    1 2 20
    0 2 100

    Sample output

    30

    Solution

    先用状压dp枚举选出所有sum=0的子图
    然后对每一个这样的子图进行kruskal求值最后dp统计即可

    Code

    //By Menteur_Hxy
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define LL long long
    #define M(a,b) memset(a,(b),sizeof(a))
    #define F(i,a,b) for(register LL i=(a);i<=(b);i++)
    #define E(i,u) for(register LL i=head[u];i;i=e[i].nxt)
    using namespace std;
    
    LL rd() {
        LL x=0,f=1; char c=getchar();
        while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
        while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
        return x*f;
    }
    
    const int INF=0x3f3f3f3f;
    const int N=17,M=N*N;
    int n,m,cnt;
    LL da[N],sum[1<<N],dp[1<<N],val[1<<N];
    struct edges{int fr,to,w;}e[M];
    
    int fa[N];
    int getf(int x) {return fa[x]==x?x:fa[x]=getf(fa[x]);}
    
    LL kru(int x) {
        int tot=0,ret=0,sum=0;
        F(i,0,n-1) if((x>>i)&1) tot++,fa[i]=i;
        F(i,1,m) if(((x>>e[i].fr)&1) && ((x>>e[i].to)&1)) {
        	int fx=getf(e[i].fr),fy=getf(e[i].to);
        	if(fx!=fy) {
        		fa[fx]=fy;
        		ret++;
        		sum+=e[i].w;
    		}
    	}
        if(ret+1<tot) return INF;
        return sum;
    }
    
    bool cmp(edges a,edges b) {return a.w<b.w;}
    
    int main() {
        n=rd(),m=rd();
        F(i,0,n-1) da[i]=rd(); 
        F(i,1,m) e[i].fr=rd(),e[i].to=rd(),e[i].w=rd();
        sort(e+1,e+1+m,cmp);
        LL MAX=(1<<n)-1;
        F(i,0,MAX) F(j,0,n-1) if((i>>j)&1) sum[i]+=da[j];
        F(i,0,MAX) 
            if(!sum[i]) val[i]=kru(i);
            else val[i]=INF;
        F(i,0,MAX) dp[i]=INF;dp[0]=0;
        F(i,0,MAX) if(!sum[i]) //这里必须加判断否则会T qwq 
    		F(j,1,MAX) if(!sum[j])
            dp[i|j]=min(dp[i|j],dp[i]+val[j]);
        if(dp[MAX]==INF) return printf("Impossible"),0;
        else printf("%lld",dp[MAX]);
        return 0;
    }
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    [C语言]数据类型与计算
    [C语言]变量VS常量
    [C语言]在命令行编译执行程序
    [cocos2d-x]游戏开发基础(图)
    [cocos2d-x]移动平台游戏开发(图)
    [cocos2d-x]认识游戏开发(图)
    [jQ/PHP]再谈使用JS数组储值的运用(提交PHP处理)
    [Nginx]Nginx的基本配置与优化1(完整配置示例与虚拟主机配置)
    [JS]如何理解JS中的类和对象
    [jPlayer]一分钟部署jPlayer
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9291134.html
Copyright © 2011-2022 走看看