BZOJ 4006: [JLOI2015]管道连接
斯坦纳树+子集DP
spfa 9272ms
Dijkstra 13016ms
luogu Dijkstra 直接TLE
综上所述斯坦纳树直接spfa
#include<cstdio> #include<algorithm> using namespace std; int Num,cnt,n,m,p,F[1005][2005],stack[1000005],instack[1005],last[1005],sta[15],cost[2005],G[2005],c[15]; struct node1{ int c,id; }q[15]; struct node{ int to,next,val; }e[6005]; void add(int a,int b,int c){ e[++cnt].to=b; e[cnt].next=last[a]; e[cnt].val=c; last[a]=cnt; } void dfs(int t,int x,int y){ if (t>Num){ G[x]=cost[y]; return; } dfs(t+1,x<<1,y); dfs(t+1,x<<1|1,y|sta[t]); } int main(){ scanf("%d%d%d",&n,&m,&p); for (int i=1; i<=m; i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } for (int i=0; i<p; i++) scanf("%d%d",&q[i].c,&q[i].id); for (int st=1; st<=n; st++) for (int i=0; i<(1<<p); i++) F[st][i]=1e9; for (int i=0; i<p; i++) F[q[i].id][1<<i]=0; for (int i=1; i<=n; i++) F[i][0]=0; for (int i=0; i<(1<<p); i++){ for (int st=1; st<=n; st++) for (int j=i; j; j=(j-1)&i) F[st][i]=min(F[st][i],F[st][j]+F[st][i^j]); int head=0,tail=0; for (int st=1; st<=n; st++) stack[++tail]=st; for (int st=1; st<=n; st++) instack[st]=1; while (head<tail){ int x=stack[++head]; instack[x]=0; for (int I=last[x]; I; I=e[I].next){ int V=e[I].to; if (F[V][i]>F[x][i]+e[I].val){ F[V][i]=F[x][i]+e[I].val; if (!instack[V]){ instack[V]=1; stack[++tail]=V; } } } } } for (int i=0; i<(1<<p); i++) cost[i]=1e9; for (int i=0; i<(1<<p); i++) for (int st=1; st<=n; st++) cost[i]=min(cost[i],F[st][i]); for (int i=1; i<=p; i++) c[i]=q[i-1].c; sort(c+1,c+p+1); Num=unique(c+1,c+p+1)-c-1; for (int i=0; i<p; i++) q[i].c=lower_bound(c+1,c+Num+1,q[i].c)-c; for (int i=0; i<p; i++) sta[q[i].c]|=(1<<i); for (int i=0; i<(1<<Num); i++) G[i]=1e9; dfs(1,0,0); for (int i=0; i<(1<<Num); i++) for (int j=i; j; j=(j-1)&i) G[i]=min(G[i],G[j]+G[i^j]); printf("%d\n",G[(1<<Num)-1]); return 0; }