bzoj4774 修路

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;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/107414096