tyvj 2054 [Nescafé29]四叶草魔杖

http://www.elijahqi.win/archives/1395
背景

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

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

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

输出一个整数表示答案。无解输出Impossible。
测试样例1

输入
3 3
50 -20 -30
0 1 10
1 2 20
0 2 100
输出
30
备注

对于 50% 的数据,2<=N<=8。
对于 100% 的数据,2<=N<=16,0<=M<=N*(N-1)/2,0<=pi,qi

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while (ch<'0'||ch>'9') {if (ch=='-')f=-1;ch=gc();}
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
    return x*f;
}
int fa[20],dp[1<<18],n,m,a[20],bin[20],h[20],num;
inline int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
struct node{
    int x,y,next,z;
}data[400],data1[400];
inline bool cmp(node a,node b){return a.z<b.z;}
int main(){
    //freopen("clover.in","r",stdin);
    n=read();m=read();memset(dp,0x3f,sizeof(dp));
    for (int i=0;i<=n;++i) bin[i]=1<<i;
    for (int i=0;i<n;++i) {
        a[i]=read();if (!a[i]) dp[bin[i]]=0;
    }
    for (int i=1;i<=m;++i){
        int x=read(),y=read(),z=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;data[num].z=z;data[num].x=x;
    }
    for (int s=1;s<=bin[n]-1;++s){
        int ans=0;
        for (int i=0;i<n;++i) if (bin[i]&s) ans+=a[i];
        if (!ans){
            num=0;int cnt=0;
            for (int i=0;i<n;++i) if (bin[i]&s) {
                fa[i]=i;cnt++;
                for (int j=h[i];j;j=data[j].next){
                    int y=data[j].y;
                    if (bin[y]&s) data1[++num]=data[j];
                }
            }int tmp=0;int tot=0;
            sort(data1+1,data1+num+1,cmp);
            /*if (s==bin[2]+bin[3]+bin[4]){
                for (int i=1;i<=num;++i) printf("%d %d %d\n",data1[i].x,data1[i].y,data1[i].z);
                printf("%d %d %d\n",fa[2],fa[3],fa[4]);
            }*/
            for (int i=1;i<=num;++i){
                int xx=find(data1[i].x),yy=find(data1[i].y);
                if (xx!=yy){
                    fa[xx]=yy;tmp+=data1[i].z;
                    if (++tot==cnt-1) {dp[s]=tmp;break;}
                }
            }
        }
    }
    //for (int s=1;s<=bin[n]-1;++s) if (dp[s]!=0x3f3f3f3f) printf("%d\n",dp[s]);
    for (int s=0;s<=bin[n]-1;++s){
        if (dp[s]==0x3f3f3f3f) continue;
        int ss=s^(bin[n]-1);
        for (int s1=ss;s1>0;s1=ss&(s1-1)){
            dp[s1|s]=min(dp[s1|s],dp[s1]+dp[s]);
        }
    }
    if (dp[bin[n]-1]==0x3f3f3f3f) printf("Impossible");else
    printf("%d",dp[bin[n]-1]);
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值