[题解]宝藏(状压
数据范围小,不是爆搜就是状压
发现每个集合s不能表示所有状态,还有一个状态是和起始点的距离,这样我们直接用$f[x][s][d]$表示点x在点集s深度为d的最小代价,暴力枚举每个起始点直接扩展状态,把s跑满就更新答案,图上所以dfs实现还好写
#include<bits/stdc++.h> #define ll long long using namespace std; const int inf=1e9+7; const int maxn=15; int n,m,g[maxn][maxn],ans=inf,lim; int dis[maxn],f[maxn][1<<maxn][maxn];//x在点集s中深度为k的最小代价 inline void dfs(int s,int sum,int dep){ if(sum>=ans)return; if(s==lim){ans=sum;return;} for(int i=1;i<=n;i++){ if(!(1<<(i-1)&s))continue; for(int j=1;j<=n;j++) if(!(1<<(j-1)&s)&&g[i][j]!=0x3f3f3f3f)//没有选过j且ij之间有边 if(f[j][1<<(j-1)|s][dep+1]>sum+dis[i]*g[i][j]){ f[j][1<<(j-1)|s][dep+1]=sum+dis[i]*g[i][j]; dis[j]=dis[i]+1; dfs(1<<(j-1)|s,f[j][1<<(j-1)|s][dep+1],dep+1); } } } int main(){ scanf("%d%d",&n,&m);lim=(1<<n)-1; memset(g,0x3f,sizeof(g)); for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); g[u][v]=g[v][u]=min(g[u][v],w); } for(int i=1;i<=n;i++){ memset(dis,0x3f,sizeof(dis)); memset(f,0x3f,sizeof(f)); dis[i]=1; dfs(1<<(i-1),0,0); } printf("%d",ans); }