【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  阅读(...)  评论(...编辑  收藏