题目意思就是在一个无向图内求一个权值最小的且包含所有点的双联通子图。
DP乱搞,拆边双联通成链,与下一个子问题。状态压缩选择边的情况。貌似写了很多无用的DP。。。毕竟最后AC时我都不明觉厉。。
这种DP+图论神题还是少做吧,要夭寿的。
推荐这篇blog
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define clr(x) memset((x),0,sizeof(x))
#define clt(x) memset((x),0x1f,sizeof(x))
#define smin(x,y) (x)=min((x),(y))
#define smax(x,y) (x)=max((x),(y))
using namespace std;
const int N = 13;
const int M = 1<<13;
const int W = 50;
const int V = 1<<28;
int T,n,m;
struct data{
int to,next,val;
}E[W<<2];
int head[M],tot;
int h[N][M][2],g[M][N][N],p[M][N][N],f[M];
void addedge(int u,int v,int z){
E[++tot].to=v,E[tot].next=head[u],E[tot].val=z,head[u]=tot;
E[++tot].to=u,E[tot].next=head[v],E[tot].val=z,head[v]=tot;
}
void init(){
tot=0,clr(head),clr(h),clt(g),clr(p),clt(f);
}
bool DP_JU(int x,int y){
return x>>(y-1)&1;
}
void DP_init(){
for(register int i=1;i<=n;i++)
for(int j=0;j<(1<<n);j++){
int u=V,v=V;
for(register int rt=head[i];rt;rt=E[rt].next)
if((j>>(E[rt].to-1)&1))
if(E[rt].val<u)v=u,u=E[rt].val;
else smin(v,E[rt].val);
h[i][j][0]=u,h[i][j][1]=v;
}
for(register int i=1;i<=n;i++)p[1<<(i-1)][i][i]=g[1<<(i-1)][i][i]=0;
}
void DP_FOR_CUT(){
for(register int i=1;i<=n;i++)p[1<<(i-1)][i][i]=0;
for(register int cut=1;cut<(1<<n);cut++)
for(register int i=1;i<=n;i++)if(DP_JU(cut,i))
for(register int j=1;j<=n;j++)if(DP_JU(cut,j)){
for(int rt=head[i];rt;rt=E[rt].next)
if(DP_JU(cut,E[rt].to))
smax(p[cut&(1<<(E[rt].to-1))][E[rt].to][j],p[cut][i][j]+E[rt].val);
for(int rt=head[j];rt;rt=E[rt].next)
if(DP_JU(cut,E[rt].to))
smax(p[cut&(1<<(E[rt].to-1))][i][E[rt].to],p[cut][i][j]+E[rt].val);
}
}
void DP_FOR_SPLIT(){
for(register int i=1;i<=n;i++)g[1<<(i-1)][i][i]=0;
for(register int split=1;split<(1<<n);split++)
for(register int i=1;i<=n;i++)if(DP_JU(split,i))
for(register int j=1;j<=n;j++)if(DP_JU(split,j)){
for(int rt=head[i];rt;rt=E[rt].next)
if(!DP_JU(split,E[rt].to))
smin(g[split|(1<<(E[rt].to-1))][E[rt].to][j],g[split][i][j]+E[rt].val);
for(int rt=head[j];rt;rt=E[rt].next)
if(!DP_JU(split,E[rt].to))
smin(g[split|(1<<(E[rt].to-1))][i][E[rt].to],g[split][i][j]+E[rt].val);
}
}
void DP_FOR_LINK(){
for(register int i=1;i<=n;i++)f[1<<(i-1)]=0;
for(register int link=1;link<(1<<n);link++){
int u=((1<<n)-1)^link;
for(register int k=u;k;k=(--k)&u)
for(register int i=1;i<=n;i++)if(DP_JU(k,i))
for(register int j=1;j<=n;j++)if(DP_JU(k,j))
if(i^j)smax(f[link^k],f[link]+p[k][i][j]+h[i][link][0]+h[j][link][0]);
else smax(f[link^k],f[link]+p[k][i][j]+h[i][link][0]+h[i][link][1]);
}
}
void DP_FOR_MERGE(){
for(register int i=1;i<=n;i++)f[1<<(i-1)]=0;
for(register int merge=1;merge<(1<<n);merge++){
int u=((1<<n)-1)^merge;
for(register int k=u;k;k=(--k)&u)
for(register int i=1;i<=n;i++)if(DP_JU(k,i))
for(register int j=1;j<=n;j++)if(DP_JU(k,j))
if(i^j)smin(f[merge^k],f[merge]+g[k][i][j]+h[i][merge][0]+h[j][merge][0]);
else smin(f[merge^k],f[merge]+g[k][i][j]+h[i][merge][0]+h[i][merge][1]);
}
}
inline void read(int &res){
static char ch;int flag=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
int main(){
read(T);
while(T--){
int x,y,z;init();
read(n),read(m);
for(register int i=1;i<=m;i++)
read(x),read(y),read(z),addedge(x,y,z);
DP_init();
DP_FOR_CUT();
DP_FOR_LINK();
DP_FOR_SPLIT();
DP_FOR_MERGE();
if(f[(1<<n)-1]>=V)cout<<"impossible"<<endl;
else cout<<f[(1<<n)-1]<<endl;
}
return 0;
}