题解:P10949 四叶草魔杖
题目传送门。
紫题认真的吗?
思路
对于一个点集
可以用子集 exp 优化到
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int Maxn=110;
const ll inf=1e15;
int n,m;
int a[Maxn];
int G[Maxn][Maxn];
ll g[1<<16|5];
struct edg{
int u,v,w;
}E[Maxn];
int tot,f[Maxn];
int qfind(int key){
return f[key]==key?key:f[key]=qfind(f[key]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
memset(G,-1,sizeof G);
for(int i=0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u][v]=w;
}
for(int i=0;i<(1<<n);i++){
tot=0; ll sm=0;
for(int j=0;j<n;j++) f[j]=j;
for(int j=0;j<n;j++) if(i>>j&1) sm+=a[j];
if(sm!=0){
g[i]=inf;
continue;
}
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
if(G[j][k]!=-1 and i>>j&1 and i>>k&1)
E[++tot]=(edg){j,k,G[j][k]};
sort(E+1,E+tot+1,[](edg x,edg y){
return x.w<y.w;
});
ll ret=0; int cnt=0;
for(int j=1;j<=tot;j++){
int u=qfind(E[j].u),v=qfind(E[j].v);
if(qfind(u)!=qfind(v)){
f[v]=u; ++cnt;
ret+=E[j].w;
}
}
int p=__builtin_popcount(i);
if(cnt==p-1) g[i]=ret; else g[i]=inf;
}
for(int i=0;i<(1<<n);i++)
for(int j=i;j;j=i&(j-1))
g[i]=min(g[i],g[i^j]+g[j]);
ll ans=g[(1<<n)-1];
if(ans==inf){
puts("Impossible");
return 0;
}
printf("%lld",ans);
return 0;
}