题: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 ",f[all]); return 0; }