「JLOI2015」管道连接(求相同颜色的点联通即可,合并斯坦纳树)

题:https://loj.ac/problem/2110

题意:给定无向图,要求选一些边,让指定的相同颜色的点联通。

分析:

   在求解单一的斯坦纳树,我们可以得到连接起点的子集的最小值g[];

   然后就针对颜色集f[];

   若某个状态set要组成x颜色和y颜色,那么f[]初始为在g中x颜色对应的点集和y颜色对应的点集;

   最后对f[]进行枚举子集更新最小值;

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
typedef long long ll;
const int mod=1e9+7;
const int M=1e3+100;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
int dp[M][M];
struct qnode{
    int v;
    ll c;
    qnode(int _v=0,ll _c=0):v(_v),c(_c){}
    bool operator <(const qnode &r)const{
     return c>r.c;
    }
};
struct Edge{
    int v;
    ll cost;
    Edge(int _v=0,ll _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[M];
bool vis[M];
priority_queue<qnode>que;
void Dij(int cursta){
    memset(vis,false,sizeof(vis));
    qnode tmp;
    while(!que.empty()){
        tmp=que.top();
        que.pop();
        int u=tmp.v;
        if(vis[u])continue;
            vis[u]=true;
        for(int i=0;i<E[u].size();i++){
            int v=E[tmp.v][i].v;
            int cost=E[u][i].cost;
            if(!vis[v]&&dp[v][cursta]>dp[u][cursta]+cost){
                dp[v][cursta]=dp[u][cursta]+cost;
                que.push(qnode(v,dp[v][cursta]));
            }
        }
    }
}
void addedge(int u,int v,ll w){
    E[u].push_back(Edge(v,w));
}
int C[20],all,f[M],g[M];
int main(){
    int n,m,p;
    scanf("%d%d%d",&n,&m,&p);
    for(int u,v,w,i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
        addedge(v,u,w);
    }
    memset(dp,0x3f,sizeof(dp));
    memset(f,0x3f,sizeof(f));
    int limit=dp[0][0];
    for(int c,d,i=1;i<=p;i++){
        scanf("%d%d",&c,&d);
        C[c]|=(1<<(i-1));
        all|=(1<<(c-1));
        dp[d][0]=dp[d][1<<(i-1)]=0;
    }
    for(int s=1;s<(1<<p);s++){
        for(int i=1;i<=n;i++){
            for(int subset=s&(s-1);subset;subset=s&(subset-1)){
                dp[i][s]=min(dp[i][s],dp[i][subset]+dp[i][s^subset]);
            }
            if(dp[i][s]<limit) que.push(qnode(i,dp[i][s]));
        }
        Dij(s);
        g[s]=inf;
        for(int i=1;i<=n;i++)
            g[s]=min(g[s],dp[i][s]);
    }
    for(int s=all;s;s=all&(s-1)){
        int sum=0;
        for(int i=1;i<=p;i++)
            if((s>>(i-1)) & 1) sum|=C[i];
        f[s]=g[sum];
    }
    for(int s=1;s<=all;s++)
        for(int subset=s&(s-1);subset;subset=s&(subset-1))
            f[s]=min(f[s],f[s^subset]+f[subset]);
    printf("%d\n",f[all]);
    return 0;
}
View Code

 

posted @ 2020-10-10 16:45  starve_to_death  阅读(123)  评论(0编辑  收藏  举报