解法:斯坦纳树,再对得到的生成树dp,因为有可能是森林的解更优
#include"bits/stdc++.h"
using namespace std;
const int N = 55;
const int inf = 0x3f3f3f3f;
int n,m,k;
int head[N],vis[N];
int f[N][1<<10],st[N],dp[1<<10];
queue<int> q;
struct edge{
int nxt,v,w;
edge(){}
edge(int nxt, int v, int w):nxt(nxt),v(v),w(w){}
}E[2111];
int tail;
inline void init()
{
tail = 0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(st,0,sizeof(st));
}
inline void add(int u, int v, int w)
{
E[tail] = edge(head[u],v,w); head[u] = tail++;
}
void spfa(int sta)
{
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = E[i].nxt){
int v = E[i].v, w = E[i].w;
if(f[v][sta] > f[u][sta] + w){
f[v][sta] = f[u][sta] + w;
if(!vis[v]){
vis[v] = 1;
q.push(v);
}
}
}
vis[u] = 0;
}
}
//预处理出st数组点的集合和f数组,不同的题目有所不同,返回最大的集合值
int prepare(int S)
{
int cc = k+1;
for(int i = 1; i <= n; i++)
for(int j = 0; j < S; j++)
f[i][j] = inf;
for(int i = 1; i <= k; i++)
st[i] = 1<<(i-1), f[i][st[i]] = 0;
for(int i = n-k+1; i <= n; i++, cc++)
st[i] = 1<<(cc-1), f[i][st[i]] = 0;
}
void stenier(int S)
{
prepare(S);
for(int sta = 0; sta < S; sta++){
for(int i = 1; i <= n; i++){
for(int s = sta&(sta-1); s; s = (s-1)&sta){
f[i][sta] = min(f[i][sta],f[i][sta-s]+f[i][s]);
}
if(f[i][sta] != inf) q.push(i), vis[i] = 1;
}
spfa(sta);
}
}
bool check(int s)
{
int ans = 0;
for(int i = 0; i < k; i++){
if(s&(1<<i)) ans++;
if(s&(1<<(i+k))) ans--;
}
return (ans == 0);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= m; i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
int S = 1<<(2*k);
stenier(S);
for(int sta = 0; sta < S; sta++){
dp[sta] = inf;
for(int i = 1; i <= n; i++)
dp[sta] = min(dp[sta],f[i][sta]);
}
for(int sta = 0; sta < S; sta++) if(check(sta)){
for(int s = sta&(sta-1); s; s = (s-1)&sta) if(check(s)){
dp[sta] = min(dp[sta],dp[s]+dp[sta-s]);
}
}
if(dp[S-1] == inf) printf("No solution\n");
else printf("%d\n",dp[S-1]);
}
return 0;
}