近期更新可能会比较少,只会更新新的知识点,因为要尽快多刷一些题。。。。
详解请参照:详解
然后按照思路,自己搞的份模版。
/*
* Steiner Tree:求,使得指定K个点连通的生成树的最小总权值
* st[i] 表示顶点i的标记值,如果i是指定集合内第m(0<=m<K)个点,则st[i]=1<<m
* endSt=1<<K
* dptree[i][state] 表示以i为根,连通状态为state的生成树值
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 50+7;
const int inf = 1e8;
typedef long long LL;
struct node
{
int v,w;
};
vector<node>head[MAXN];
int n,m,k;
int R;
int dp[MAXN][1<<10];
int d[1<<10];
int s[MAXN];
void init()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; ++i)
{
head[i].clear();
s[i] = 0;
}
R = 1<<(k<<1);
for(int i = 1; i <= n; ++i)
for(int j = 0; j < R; ++j)dp[i][j] = inf;
int u,v,w;
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
head[u].push_back(node{v,w});
head[v].push_back(node{u,w});
}
for(int i = 1; i <= k; ++i)
{
s[i] = 1<<(i-1),dp[i][s[i]] = 0;
s[n-i+1] = 1<<(k+i-1),dp[n-i+1][s[n-i+1]] = 0;
}
}
bool check(int state)
{
int sum = 0;
for(int i = 0; state ; i++,state>>=1)
{
sum += (state&1)*(i<k?1:-1);
}
return sum == 0;
}
bool updata(int x,int y,int w)
{
if(w < dp[x][y])
{
dp[x][y] = w;
return 1;
}
return 0;
}
queue<int>q;
bool vis[MAXN][1<<10];
void spfa(int state)
{
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u][state] = 0;
for(node x : head[u])
{
int v = x.v;
int w = x.w;
if(updata(v,s[v]|state,dp[u][state] + w) && state == (state|s[v]) && !vis[v][state])
{
vis[v][state] = 1;
q.push(v);
}
}
}
}
void steinerTree()
{
for(int state = 0; state < R; ++state)
{
for(int i = 1; i <= n; ++i)
{
for(int j = (state-1)&state; j; j = (j-1)&state)
{
//printf("%d %d %d %d\n",i,j|s[i],i,(state-j)|s[i]);
dp[i][state] = min(dp[i][state],dp[i][j|s[i]] + dp[i][(state-j)|s[i]]);
}
if(dp[i][state] < inf)q.push(i),vis[i][state] = 1;
}
spfa(state);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
steinerTree();
for(int state = 0; state < R; ++state)
{
d[state] = inf;
for(int i = 1; i <= n; ++i)d[state] = min(d[state],dp[i][state]);
}
for(int state = 1; state < R; ++state)
{
if(check(state))
{
for(int sub = (state-1)&state; sub; sub = (sub-1)&state)
{
if(check(sub))d[state] = min(d[state],d[sub] + d[state - sub]);
}
}
}
if(d[R-1] >= inf)puts("No solution");
else printf("%d\n",d[R-1]);
}
return 0;
}