【BZOJ4006】管道连接(动态规划,斯坦纳树)

题面

BZOJ
洛谷

题解

这题区别不是很大吧。
基本上拿过来改一下就做完了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
#define ll long long
#define MAX 1100
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,p;
struct Line{int v,next,w;}e[MAX<<3];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int f[1<<10][MAX],g[1<<10];
bool vis[MAX];
queue<int> Q;
map<int,int> M;
int fz[MAX],St[20],G[20];
void SPFA(int *f)
{
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();
		for(int i=h[u];i;i=e[i].next)
			if(f[e[i].v]>f[u]+e[i].w)
			{
				f[e[i].v]=f[u]+e[i].w;
				if(!vis[e[i].v])Q.push(e[i].v),vis[e[i].v]=true;
			}
		vis[u]=false;
	}
}
bool check(int s)
{
	for(int i=1;i<=p;++i)
		if((s&G[i])!=0&&(s&G[i])!=G[i])
			return false;
	return true;
}
int main()
{
	n=read();m=read();p=read();
	memset(f,63,sizeof(f));memset(g,63,sizeof(g));
	for(int i=1;i<=m;++i)
	{
		int u=read(),v=read(),w=read();
		Add(u,v,w);Add(v,u,w);
	}
	for(int i=1;i<=p;++i)
	{
		int c=read(),d=read();
		fz[d]=c;M[d]=i-1;St[i]=d;
		f[1<<(i-1)][d]=0;
	}
	for(int i=1;i<=p;++i)
		for(int j=1;j<=p;++j)
			if(fz[St[i]]==fz[St[j]])
				G[i]|=1<<M[St[j]];
	int S=1<<p;
	for(int i=0;i<S;++i)
	{
		for(int j=1;j<=n;++j)
		{
			for(int k=i&(i-1);k;k=(k-1)&i)
				f[i][j]=min(f[i][j],f[k][j]+f[i^k][j]);
			if(f[i][j]<=1e9)Q.push(j),vis[j]=true;
		}
		SPFA(f[i]);
		for(int j=1;j<=n;++j)g[i]=min(g[i],f[i][j]);
	}
	for(int i=0;i<S;++i)
		for(int t=(i-1)&i;t;t=(t-1)&i)
			if(check(t)&&check(i^t))
				g[i]=min(g[i],g[t]+g[i^t]);
	printf("%d\n",g[S-1]<=1e9?g[S-1]:-1);
	return 0;
}

posted @ 2018-09-18 17:21  小蒟蒻yyb  阅读(178)  评论(0编辑  收藏