1 条题解
-
0
自动搬运
来自洛谷,原作者为

Polarisx
一位努力不落后的 NPC搬运于
2025-08-24 23:02:50,当前版本为作者最后更新于2025-08-18 21:18:49,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
紫题认真的吗?
思路
对于一个点集 ,要让它能量归零当且仅当这个点集的 和为 ,最小代价显然是该点集导出子图的最小生成树边权之和,容易发现最终选择的边一定是由若干个最小生成树拼凑而成的,再结合数据范围,我们可以直接上子集 DP,时间复杂度 。
可以用子集 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; }
- 1
信息
- ID
- 10145
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者