bzoj没了,(悲
https://darkbzoj.tk/problem/4774
理解了好久斯坦纳树的求法,学习自牛逼网友yybhttps://www.cnblogs.com/cjyyb/p/9670025.html
跑出斯坦纳树以后,这题要求的是i和n-i+1相通,所以还存在最短路森林情况可能是最优解,所以最后要枚举一遍子集
#include<bits/stdc++.h>
using namespace std;
const int maxl=1e4+10;
int n,m,D,inf,ans;
int f[1<<8][maxl],g[1<<8];
struct ed{int to,l;};
vector<ed> e[maxl];
bool in[maxl];
queue<int> q;
inline void prework()
{
scanf("%d%d%d",&n,&m,&D);
int u,v,l;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&l);
e[u].push_back(ed{v,l});
e[v].push_back(ed{u,l});
}
}
inline void spfa(int *f)
{
int u,v;
while(!q.empty())
{
u=q.front();q.pop();
for(ed d:e[u])
{
v=d.to;
if(f[v]<=f[u]+d.l)
continue;
f[v]=f[u]+d.l;
if(!in[v])
q.push(v),in[v]=true;
}
in[u]=false;
}
}
inline bool ck(int s){return (s&(1<<D)-1)==(s>>D);}
inline void mainwork()
{
memset(f,0x3f,sizeof(f));
memset(g,0x3f,sizeof(g));
inf=f[0][0];
for(int i=1;i<=D;i++)
f[1<<(i-1)][i]=f[1<<(D+i-1)][n-i+1]=0;
int up=1<<(D*2);
for(int s=0;s<up;s++)
{
for(int i=1;i<=n;i++)
{
for(int t=s&(s-1);t;t=(t-1)&s)
f[s][i]=min(f[s][i],f[t][i]+f[s^t][i]);
if(f[s][i]<inf)
q.push(i),in[i]=true;
}
spfa(f[s]);
for(int i=1;i<=n;i++)
g[s]=min(g[s],f[s][i]);
}
for(int s=0;s<up;s++)
for(int t=(s-1)&s;t;t=(t-1)&s)
if(ck(t) && ck(s^t))
g[s]=min(g[s],g[t]+g[s^t]);
ans=g[up-1];
if(ans==inf)
ans=-1;
}
inline void print()
{
printf("%d",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}