如果没有类别限制的话,就是裸的斯坦纳树。加上类别限制以后,因为最多有 5 <script type="math/tex" id="MathJax-Element-11">5</script>种真正有用的类别,对这些类别暴力dfs哪些联通就可以了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1010,max2=1100,oo=0x3f3f3f3f;
vector<pair<int,int> > to[maxn];
queue<int> q;
int dp[maxn][max2],g[max2],f[15],a[15],cnt[15],s[15],tag[maxn],n,m,k,num,ans=oo;
void dfs(int p)
{
int x;
if (p==k+1)
{
int t=0;
for (int i=1;i<=num;i++) t+=g[s[i]];
ans=min(ans,t);
return;
}
if (cnt[p]<2)
{
dfs(p+1);
return;
}
for (int i=1;i<=num;i++)
{
x=s[i];
s[i]|=a[p];
dfs(p+1);
s[i]=x;
}
s[++num]=a[p];
dfs(p+1);
num--;
}
int main()
{
//freopen("c.in","r",stdin);
int u,v,x;
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&x);
to[u].push_back(make_pair(v,x));
to[v].push_back(make_pair(u,x));
}
memset(dp,0x3f,sizeof(dp));
for (int i=0;i<k;i++)
{
scanf("%d%d",&x,&f[i]);
cnt[x]++;
a[x]|=1<<i;
dp[f[i]][1<<i]=0;
tag[f[i]]=1;
}
for (int i=1;i<=n;i++)
if (!tag[i]) dp[i][0]=0;
for (int S=0;S<(1<<k);S++)
{
for (int i=1;i<=n;i++)
for (int T=S&(S-1);T;T=S&(T-1))
dp[i][S]=min(dp[i][S],dp[i][T]+dp[i][S^T]);
for (int i=1;i<=n;i++)
if (dp[i][S]<oo) q.push(i);
while (!q.empty())
{
u=q.front();
q.pop();
for (vector<pair<int,int> >::iterator it=to[u].begin();it!=to[u].end();++it)
{
v=(*it).first;
x=dp[u][S]+(*it).second;
if (x<dp[v][S])
{
dp[v][S]=x;
q.push(v);
}
}
}
g[S]=oo;
for (int i=1;i<=n;i++) g[S]=min(g[S],dp[i][S]);
}
dfs(1);
printf("%d\n",ans);
}