传送门:luogup3959
n≤12 n ≤ 12 ,预处理从任意一个连通块(非全集)连向另一个无交集的连通块中的每一个点的最小费用 F[i][j] F [ i ] [ j ] ( i,j i , j 二进制分别表示连出和连入连通块)。枚举起点,按层 dfs d f s ,每次记录当前层点,枚举下一层来更新答案。
#include
#define gc getchar()
#define si isdigit(c)
using namespace std;
const int N=(1<<12)+10,inf=0x3f3f3f3f;
int n,m,G[15][15],bin[15],a[15],num,dis[15];
int S,ct[15],cnt,ans=inf,F[N][N],to[N],d[N][15];
char c;
inline void rd(int &x)
{
c=gc;x=0;
for(;!si;c=gc);
for(;si;c=gc) x=x*10+(c^48);
}
inline void bd(int pos,int s,int id,int cn)
{
if(pos==n) return;
int i,j,k,z,ori=cn,nw;
for(i=pos;ifor(j=0;jfor(j=0;jif((!(s&bin[j])) && i!=j && G[i][j]if((!(cn&bin[j]))) cn|=bin[j];
}
if(cn&bin[i]) cn-=bin[i];
to[s|bin[i]]=cn;
for(j=cn;j;j=(j-1)&cn){
for(z=0,k=0;kif(j&bin[k]) z+=d[nw][k];
F[s|bin[i]][j]=z;
}
bd(i+1,s|bin[i],nw,cn);
}
}
inline void dfs(int dep,int s,int pre,int sum)
{
if(sum>=ans) return;
if(s==S){ans=sum;return;}
int i,j,lim=to[pre]&(S&(~s));
for(i=lim;i;i=(i-1)&lim) dfs(dep+1,s|i,i,sum+dep*F[pre][i]);
}
int main(){
int i,j,k,x,y,z,s,res;
memset(G,0x3f,sizeof(G));
memset(F,0x3f,sizeof(F));
rd(n);rd(m);
bin[0]=1;for(i=1;i<=n;++i) bin[i]=bin[i-1]<<1;
for(i=1;i<=m;++i){
rd(x);rd(y);rd(z);x--;y--;
G[x][y]=G[y][x]=min(G[x][y],z);
}
S=(1<1;
memset(d[0],0x3f,sizeof(d[0]));
bd(0,0,0,0);
for(i=0;i1,bin[i],bin[i],0);
printf("%d\n",ans);
return 0;
}