【BZOJ4006】管道连接(动态规划,斯坦纳树)
题面
题解
和这题区别不是很大吧。
基本上拿过来改一下就做完了。
#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;
}