四叶草魔杖
问题:
魔杖护法\(Freda\)融合了四件武器,于是魔杖顶端缓缓地生出了一棵四叶草,四片叶子幻发着淡淡的七色光。圣剑护法\(rainbow\)取出了一个圆盘,圆盘上镶嵌着N颗宝石,编号为\(0-N-1\)。第i颗宝石的能量是\(Ai\)。如果\(Ai>0\),表示这颗宝石能量过高,需要把\(Ai\)的能量传给其它宝石;如果\(Ai<0\),表示这颗宝石的能量过低,需要从其它宝石处获取\(-Ai\)的能量。保证\(\sum Ai\)\(=0\)。只有当所有宝石的能量均相同时,把四叶草魔杖插入圆盘中央,才能开启超自然之界的通道。
不过,只有\(M\)对宝石之间可以互相传递能量,其中第\(i\)对宝石之间无论传递多少能量,都要花费\(Ti\)的代价。探险队员们想知道,最少需要花费多少代价才能使所有宝石的能量都相同?
解
我们注意到 此题\(Ai\)的总和为\(0\) 画个图可知 一条边最多进行一次传递 要想代价最小应该 要删边使得 一点权和为\(0\)的连通图边权值最小
答案是由一个一个权值和为\(0\)的连通图组成的 并且\(n\)很小
所以想到了\(kruskal\)和状态压缩 \(DP\)
code:
#include<bits/stdc++.h> using namespace std; #define maxnn 66666 #define inf 10000000 int f[maxnn]; int dp[maxnn]; int a[maxnn]; int cnt=0; int all=0; struct node { int st,en,w; }e[maxnn]; int n, m; int sum[maxnn]; bool cmp(node a ,node b) { return a.w<b.w; } int gf(int v) { return f[v]==v?v:f[v]=gf(f[v]); } int krus(int v,int num) { int www=0; for(int i=1;i<=n;i++) { f[i]=i; } for(int i=1;i<=cnt;i++) { if(((1<<e[i].st-1)&v)&&((1<<e[i].en-1)&v)) { if(gf(e[i].st)!=gf(e[i].en)) { num--; int fx=gf(e[i].st); f[fx]=gf(e[i].en); www+=e[i].w; } } } int ans=0; if(num==1) return www; else return inf; } int main() { int x,y,z; cin>>n>>m; all=(1<<n)-1; for(int i=1;i<=n;i++) { cin>>a[i]; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); x++,y++; e[++cnt].st=x; e[cnt].en=y; e[cnt].w=z; } for(int i=0;i<=all;i++) sum[i]=inf,dp[i]=inf; sort(e+1,e+1+cnt,cmp); for(int i=0;i<=all;i++) { int sumM=0,tot=0; for(int j=1;j<=n;j++) if((1<<j-1)&i) { sumM+=a[j]; tot++; } if(sumM==0&&tot) { dp[i]=krus(i,tot); sum[i]=0; } } for(int i=0;i<=all;i++) { if(sum[i]==0) { for(int j=0;j<=all;j++) { if(sum[j]==0) { dp[i|j]=min(dp[i|j],dp[i]+dp[j]); } } } } if(dp[all]!=inf) cout<<dp[all]; else cout<<"Impossible"; }