打卡信奥刷题(3522)用C++实现信奥题 P10949 四叶草魔杖

P10949 四叶草魔杖

题目描述

魔杖护法 Freda 融合了四件武器,于是魔杖顶端缓缓地生出了一棵四叶草,四片叶子幻发着淡淡的七色光。

圣剑护法 rainbow 取出了一个圆盘,圆盘上镶嵌着 NNN 颗宝石,编号为 0∼N−10 \sim N-10N1。第 iii 颗宝石的能量是 AiA_iAi

如果 Ai>0A_i > 0Ai>0,表示这颗宝石能量过高,需要把 AiA_iAi 的能量传给其它宝石;如果 Ai<0A_i < 0Ai<0,表示这颗宝石的能量过低,需要从其它宝石处获取 −Ai-A_iAi 的能量。

保证 ∑Ai=0\sum A_i = 0Ai=0

只有当所有宝石的能量均相同时,把四叶草魔杖插入圆盘中央,才能开启超自然之界的通道。

不过,只有 MMM 对宝石之间可以互相传递能量,其中第 iii 对宝石之间无论传递多少能量,都要花费 TiT_iTi 的代价。

探险队员们想知道,最少需要花费多少代价才能使所有宝石的能量都相同?

输入格式

第一行两个整数 N,MN,MN,M

第二行 NNN 个整数 AiA_iAi

接下来 MMM 行每行三个整数 pi,qi,Tip_i,q_i,T_ipi,qi,Ti,表示在编号为 pip_ipiqiq_iqi 的宝石之间传递能量需要花费 TiT_iTi 的代价。

数据保证每对 pi,qip_i,q_ipi,qi 最多出现一次。

输出格式

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

输入输出样例 #1

输入 #1

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

输出 #1

30

说明/提示

2≤N≤162 \le N \le 162N16,
0≤M≤N(N−1)20 \le M \le \dfrac{N(N-1)}{2}0M2N(N1),
0≤pi,qi<N0 \le p_i,q_i < N0pi,qi<N,
−1000≤Ai≤1000-1000 \le A_i \le 10001000Ai1000,
0≤Ti≤10000 \le T_i \le 10000Ti1000

C++实现

#include <iostream>
#include <cstring>
#include <algorithm>
#define reg register
using namespace std;
const int N=17;
int n,m,dp[1<<N],sum[1<<N],mst[1<<N],b[1<<N];
struct edge{
	int u,v,w;
} e[300];
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>m;reg int x,y,z;
	for (int i=0;i<n;++i)cin>>sum[1<<i];
	for (int i=0;i<m;++i)cin>>e[i].u>>e[i].v>>e[i].w;
	for (int i=2;i<1<<n;++i)sum[i]=sum[i^(i&-i)]+sum[i&-i];
	memset(mst,0x3f,sizeof mst);mst[0]=0;
	for (int i=0;i<n;++i)mst[1<<i]=0;
	for (int i=1;i<1<<n;++i)
		for (int j=0;j<m;++j){
			x=e[j].u;y=e[j].v;z=e[j].w;
			if (!(i&(1<<x))||!(i&(1<<y)))continue; 
			mst[i]=min({mst[i],mst[i^(1<<x)]+z,mst[i^(1<<y)]+z});
		}
	memset(dp,0x3f,sizeof dp);dp[0]=0;
	for (reg int i=1;i<1<<n;++i){
		if (sum[i])continue;
		for (x=0,y=i;y;++x,y^=y&-y)b[1<<x]=y&-y;
		for (reg int j=0;j<1<<x;++j){
			for (y=j,z=0;y;y^=y&-y)z|=b[y&-y];
			if (sum[z])continue;
			dp[i]=min(dp[i],dp[z]+mst[i^z]);
		}
	}
	if (dp[(1<<n)-1]>=0x3f3f3f3f)
		cout<<"Impossible";
	else 
		cout<<dp[(1<<n)-1];
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值